Comment puis-je exécuter une commande cron avec des variables d'environnement existantes?

114

Comment puis-je exécuter une commande cron avec des variables d'environnement existantes?

Si je suis à l'invite du shell, je peux taper echo $ORACLE_HOMEet obtenir un chemin. C’est l’une de mes variables environnementales qui est définie dans mes ~/.profile. Cependant, il semble que les ~/.profilescripts ne soient pas chargés et, par conséquent, mes scripts échouent car la $ORACLE_HOMEvariable n'est pas définie.

Dans cette question, l'auteur mentionne la création d'un ~/.cronfileprofil définissant des variables pour cron, puis il effectue une solution de contournement pour charger toutes ses commandes cron dans des scripts qu'il conserve dans son ~/Cronrépertoire. Un fichier ~/.cronfileressemble à une bonne idée, mais le reste de la réponse semble un peu lourd et j'espérais que quelqu'un pourrait me dire un moyen plus facile d'obtenir le même résultat.

Je suppose qu'au début de mes scripts, je pourrais ajouter quelque chose du genre source ~/.profilemais cela semble être redondant.

Alors, comment puis-je faire en sorte que mes scripts cron chargent les variables à partir de mon profil de shell interactif?

cwd
la source
Comment l'ajout source ~/.profileà un programme est-il redondant? Les programmes héritent de leur environnement du programme appelant. Si ce programme d’appel n’est pas votre shell, comment le programme en question obtiendra-t-il l’environnement souhaité?
Arcege
J'ai déjà écrit ma réponse à une question similaire ici. Il utilise simplement su -lpour configurer un environnement de connexion normal comprenant le $ PATH pour un utilisateur root ou autre.
tasket

Réponses:

141

Dans la crontab, avant de commander, ajoutez . $HOME/.profile. Par exemple:

0 5 * * * . $HOME/.profile; /path/to/command/to/run

Cronne sait rien de votre coquille; il est démarré par le système, il a donc un environnement minimal. Si vous voulez quelque chose, vous devez l'avoir vous-même.

Arcege
la source
14
Que fait l' .avant le script? (Je ne sais pas comment je le ferais man). Pourquoi est-ce différent de source?
cwd
25
La .commande est la commande d'origine pour source. Ils sont équivalents dans le shell et un peu plus faciles à taper, surtout dans une crontab. Pour obtenir plus d'informations, tapez help .ou recherchez ^SHELL BUILTIN COMMANDSdans la page de manuel bashou en haut de man zshbuiltins, . Running tapez .` vous dira que la commande est une commande intégrée.
Arcege
9
Selon les distributions Linux, vous devrez peut-être changer .profilepar .bash_profile. Vérifiez quel .profilefichier existe dans le répertoire de base de l'utilisateur.
Frosty Z
@Arcege Cela ne fonctionne pas pour moi (Fedora Core 21), et je suppose que c'est parce que le niveau de la coque baisse. Au lieu de cela, ce qui fonctionne, c'est si vous le sourcez.
Richard T
3
Il est probable que si cela ne fonctionne pas, c'est parce que le shell pour le script cron n'est pas défini sur bash, il ne s'exécute donc pas de la même façon que vous le souhaiteriez.
Daniel Farrell
40

Une autre option, que je trouve plus facile, consiste à exécuter le script avec cron et à inclure l’environnement dans le script.

Dans le fichier crontab -e:

SHELL=/bin/bash

*/1 * * * * $HOME/cron_job.sh

Dans le fichier cron_job.sh:

#!/bin/bash
source $HOME/.bash_profile
some_other_cmd

Toute commande après la source de .bash_profile aura votre environnement comme si vous vous étiez connecté.

Robert Brisita
la source
5
Lors de l'exécution sur une AMI Linux AWS, il ne m'est même pas venu à l'esprit que cron ne l'utilisait pas /bin/bashcomme shell. Je n'arrêtais pas de me demander pourquoi des choses comme, par exemple cd /path/to/project; source .vars, fonctionneraient lorsque je les taperais manuellement mais échoueraient ( File not found) si elles étaient incluses dans un travail cron. La ligne de touche pour moi était de régler SHELL=/bin/bashafin que je puisse réellement utiliser des commandes bash familières dans chaque travail cron. /bin/sh/(le shell par défaut, apparemment) est très limitant.
Hartley Brody
Il est dommage que vous ne puissiez pas spécifier les fichiers d'environnement en haut du cron, comme vous pouvez spécifier des variables d'environnement individuelles. Systemd a une EnvironmentFileunité de service. Dommage que cron n'ait pas quelque chose de similaire.
Radtek
vous forcez tous les scripts à utiliser / bin / bash dans tous les crontab, ce qui n’est pas une bonne idée, mais aussi en ce qui concerne votre ligne cron: * / 1 * * * * $ HOME / cron_job.sh… * / 1 est bon pour WHAT ?! une étoile signifie qu'il sera exécuté toutes les minutes / 1 moyen sera exécuté toutes les minutes, comme réponse dans une communauté intelligente c'est un vilain péché, maintenant je crois que vous êtes très confus de dire le meilleur… désolé
THESorcerer
1
C'est ce qu'on appelle un exemple. N'hésitez pas à vous adapter à vos besoins ou ne l'utilisez pas du tout. Différents traits pour différentes personnes.
Robert Brisita
4
Si $SHELLc'est le cas /bin/sh, la sourcecommande n'existe pas. Utilisez à la .place.
Melle
18

Une autre option, que je trouve plus facile, est d’exécuter le script avec cron et d'indiquer à bash de se connecter (d'où l'utilisation de /etc/profile.d/...définitions d'environnement).

En crontab -efichier:

*/1 * * * * bash -l -c './cron_job.sh'
*/1 * * * * bash -l -c 'php -f ./cron_job.php'

Toute commande après la source de .bash_profileaura votre environnement comme si vous vous êtes connecté.

Artistan
la source
10

Mauvaise idée. La pratique générale consiste à définir spécifiquement toutes les variables d'environnement requises dans un script à exécuter à partir d'un travail cron.

fpmurphy
la source
Je suis d’accord avec @fpmurphy pour dire qu’il garantit également l’environnement de processus sécurisé. Si vous souhaitez définir uniquement quelques variables à partir de cron, vous pouvez utiliser la /usr/bin/envcommande pour définir les variables, puis agir en tant que processus d’environnement pour le travail cron.
Nikhil Mulley
Daemontoolsenvdir vient aussi à l'esprit.
Sr.
6
Je suis pour la sécurité, mais je peux peut-être créer un fichier ~/.cronvarset l'inclure dans le profil ainsi que dans mes scripts cron. Je ne souhaite pas coder de manière stricte les variables d'environnement dans chacun des scripts que j'exécute car, lorsque des chemins changent, les chemins codés en dur dans chaque fichier ne sont pas faciles à gérer. On dirait que cela permettrait un emplacement centralisé pour les variables nécessaires tout en empêchant le chargement d'autres variables.
cwd
4

Cette syntaxe vous aide vraiment. Je ne comprends pas la syntaxe, mais ça marche. Oracle utilise cette syntaxe lors du déploiement d'Oracle Configuration Manager sur crontab. Par conséquent, j'estime qu'il s'agit d'une bonne solution.

0 5 * * * SOME_ENV_VAR=some_value some_command some_parameters
meir
la source
2

Je suis récemment tombé sur un cas dans lequel je devais exécuter le travail global de cron en tant que root tout en exécutant une sous-commande en tant qu'utilisateur différent (ce qui nécessitait de rechercher l'environnement de cet utilisateur). Je suis allé avec l'approche suivante:

# m  h  dom  mon  dow  user  command
*/5  *   *    *    *   root  (sudo -i -u <the user> command-to-be-run-as-user) && command-to-be-run-as-root

La partie cruciale est l'argument -iqui est passé et sudoqui exécutera la commande donnée dans un shell de connexion séparé (ce qui signifie que les fichiers de points de l'utilisateur seront générés).

PS: Notez que la usercolonne est uniquement disponible dans /etc/crontabet les /etc/cron.d/*fichiers.

balu
la source
1

La solution qui a fonctionné pour moi est décrite ici .

Vous créez un script wrapper qui appelle . ~/.cronfilepuis fait les choses que vous voulez. Ce script est lancé par cron.

Dans ~/.cronfilevous spécifiez l'environnement pour vos tâches cron.

les weekens
la source
1

Oui, vous pouvez utiliser des "solutions de contournement bien connues" (dont certaines ont été répertoriées). C’est une autre façon de dire que tout le monde sait que c’est de la merde, bien que certaines personnes qualifient cela de "dispositif de sécurité" le temps perdu n'était pas pour rien. C'est l'équivalent cron du clavier QWERTY.

Je soupçonne que la raison initiale était peut-être liée aux performances, de telle sorte que les scripts exécutés une fois par minute ne prennent pas le temps de lire des scripts rc. De plus, à l'origine, cron n'était pas vraiment configurable, donc un paramètre par défaut était vraiment la seule option.

Il n’ya pas de sécurité supplémentaire en n’ayant pas une configuration ou une méthode simple permettant à cron de s’occuper uniquement de l’environnement de votre shell interactif au lieu d’obliger les utilisateurs à effectuer une gymnastique de shell stupide. Sur une machine moderne, les gains de performance ne sont généralement pas perceptibles, sauf si vous avez une grande quantité de travaux en cours d'exécution à la minute.

La culture Unix échoue. À mon humble avis. :-)

Austin S.
la source
1
"Il n'y a pas de sécurité supplémentaire." Ce n'est pas vrai. Jetez un coup d'œil à CVE-2011-1095 , CVE-2008-4304 et CVE-2010-3847 .
En passant, j'ai voté contre votre réponse. J'essaie généralement d'éviter de déprécier les réponses des nouveaux arrivants, mais la sécurité est importante pour moi. S'il vous plaît ne prenez pas la voix vers le bas du mauvais côté. Outre la partie sur la sécurité, votre réponse est excellente et mériterait un vote positif. Vous pouvez modifier votre réponse ici si vous le souhaitez.
Rien de tout cela n'a à voir avec le fait que cron utilise un shell avec le jeu de drapeaux interactif. Ceci est pur FUD. Malheureusement, je ne peux pas réduire votre vote. Cela peut sembler une flamme, mais il est très frustrant de penser qu'un véhicule à trois roues est préférable, car la sécurité pose un problème de sécurité. Ce n'est pas. Les gens viennent de monter un tricycle depuis si longtemps qu'ils ont oublié qu'il était possible d'ajouter une quatrième roue.
Austin S.
En d'autres termes: si l'un des cerceaux supplémentaires prévus par les autres répondants suggérés est utilisé, comment ne peuvent-ils pas également accéder aux trous que vous mentionnez? "* * * * * exec bash -i -c LOCALE = ......."
Austin S.
Cela se lit comme un coup de gueule. Je ne vois même pas où cela répond à la question. Même si la partie sur la sécurité a été supprimée, @EvanTeitelman, je ne vois pas pourquoi cela mériterait un vote positif, car cela ne répond pas à la question.
Wildcard
1

Au lieu de définir le profil, ce qui m’a aidé a été de définir le PATH. Certaines des commandes n'étaient pas disponibles dans mes scripts cron, car elles PATHsont différentes.

ENVIRONMENT=prod
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
*/30 * * * * /opt/myscript1.sh
*/30 * * * * /opt/myscript2.sh
*/30 * * * * /opt/myscript3.sh

Définir PATHavec le chemin des commandes m'a aidé. Encore mieux si vous pouvez utiliser un modèle et désemployer plus tard,

ENVIRONMENT={{ENVIRONMENT}}
PATH={{PATH}}
*/30 * * * * /opt/myscript1.sh
*/30 * * * * /opt/myscript2.sh
*/30 * * * * /opt/myscript3.sh

Passer des variables à chaque élément semble compliqué.

Optimus Prime
la source
-1

Je mets . ~/.dbus/session-bus/*au sommet de mon script désiré :)

Eric
la source
1
Bienvenue chez U & L SE. Veuillez développer davantage votre réponse pour que les lecteurs en bénéficient.
Ramesh