Où puis-je définir les variables d'environnement que crontab utilisera?

266

J'ai un crontab qui fonctionne toutes les heures. L'utilisateur qui l'exécute a un environnement variable dans ce .bash_profilequi fonctionne lorsque l'utilisateur exécute le travail à partir du terminal, cependant, évidemment, ceux-ci ne sont pas récupérés par crontab lors de son exécution.

J'ai essayé de les installer .profileet .bashrcmais ils ne semblent toujours pas être récupérés. Est-ce que quelqu'un sait où je peux placer des variables d'environnement que crontab peut récupérer?

James
la source

Réponses:

88

Demandez à «cron» d'exécuter un script shell qui définit l'environnement avant d'exécuter la commande.

Toujours.

#   @(#)$Id: crontab,v 4.2 2007/09/17 02:41:00 jleffler Exp $
#   Crontab file for Home Directory for Jonathan Leffler (JL)
#-----------------------------------------------------------------------------
#Min     Hour    Day     Month   Weekday Command
#-----------------------------------------------------------------------------
0        *       *       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/hourly
1        1       *       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/daily
23       1       *       *       1-5     /usr/bin/ksh /work1/jleffler/bin/Cron/weekday
2        3       *       *       0       /usr/bin/ksh /work1/jleffler/bin/Cron/weekly
21       3       1       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/monthly

Les scripts dans ~ / bin / Cron sont tous des liens vers un seul script, 'runcron', qui ressemble à:

:       "$Id: runcron.sh,v 2.1 2001/02/27 00:53:22 jleffler Exp $"
#
#       Commands to be performed by Cron (no debugging options)

#       Set environment -- not done by cron (usually switches HOME)
. $HOME/.cronfile

base=`basename $0`
cmd=${REAL_HOME:-/real/home}/bin/$base

if [ ! -x $cmd ]
then cmd=${HOME}/bin/$base
fi

exec $cmd ${@:+"$@"}

(Écrit en utilisant une ancienne norme de codage - de nos jours, j'utiliserais un shebang '#!' Au début.)

Le '~ / .cronfile' est une variation de mon profil pour une utilisation par cron - rigoureusement non interactif et sans écho pour être bruyant. Vous pouvez organiser l'exécution du fichier .profile, etc. à la place. (La substance REAL_HOME est un artefact de mon environnement - vous pouvez prétendre que c'est la même chose que $ HOME.)

Ainsi, ce code lit l'environnement approprié, puis exécute la version non Cron de la commande à partir de mon répertoire personnel. Ainsi, par exemple, ma commande «en semaine» ressemble à:

:       "@(#)$Id: weekday.sh,v 1.10 2007/09/17 02:42:03 jleffler Exp $"
#
#       Commands to be done each weekday

# Update ICSCOPE
n.updics

La commande «quotidienne» est plus simple:

:       "@(#)$Id: daily.sh,v 1.5 1997/06/02 22:04:21 johnl Exp $"
#
#       Commands to be done daily

# Nothing -- most things are done on weekdays only

exit 0
Jonathan Leffler
la source
246

Vous pouvez définir des variables d'environnement dans la crontab elle-même lors de l'exécution à crontab -epartir de la ligne de commande.

LANG=nb_NO.UTF-8
LC_ALL=nb_NO.UTF-8
# m h  dom mon dow   command

* * * * * sleep 5s && echo "yo"

Cette fonctionnalité n'est disponible que pour certaines implémentations de cron. Ubuntu et Debian utilisent actuellement vixie-cron qui permet de les déclarer dans le fichier crontab (également GNU mcron ).

Archlinux et RedHat utilisent cronie qui ne permet pas de déclarer les variables d'environnement et générera des erreurs de syntaxe dans cron.log. Une solution de contournement peut être effectuée par entrée:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"
carestad
la source
58
Notez que vous ne pouvez pas utiliser la substitution de variables comme dans le shell, donc une déclaration comme PATH = / usr / local / bin: $ PATH est interprétée littéralement.
Zac
8
J'ai pu définir les variables d'environnement dans la crontab elle-même sous RedHat 4.4.7-3 et cronie-1.4.4-15.el6.x86_64
Bruno Lange
7
Vous n'avez pas vraiment besoin d'exporter des variables si les variables ne sont utilisées que dans la commande, ajoutez-les simplement avant votre commande. "* * * * * sommeil 5s; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL"
vutran
@BrunoLange pourriez-vous partager comment avez-vous réussi à les configurer?
Newskooler
145

J'ai une solution de plus pour ce problème:

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

Dans ce cas, il sélectionnera toutes les variables d'environnement définies dans votre $HOME/.profilefichier.

Bien sûr, $HOMEn'est pas non plus défini, vous devez le remplacer par le chemin complet de votre $HOME.

Vishal
la source
Cela a fonctionné pour moi après avoir beaucoup lutté pour trouver la réponse, merci!
vladimir montealegre
5
cela ne fonctionnait pas pour moi jusqu'à ce que je réalise que j'avais laissé de côté la période précédant $ HOME. Que fait exactement cette période?
Flymike
9
La période est équivalente à la commande "source": tldp.org/LDP/abs/html/special-chars.html#DOTREF
Jeff W
@PeterLee est-ce que tout ce qui a été mentionné a fonctionné pour vous? J'ai écrit ceci car les solutions mentionnées ci-dessus n'étaient pas efficaces pour moi. Si la solution mentionnée ci-dessus ne fonctionne pas, je devrai faire des recherches pour en trouver la raison. ;-)
Vishal
3
@Vishal En fait, cela fonctionne maintenant pour moi. J'essayais de le faire source ~/.bashrc, et il s'avère que mon .bashrcfichier est en quelque sorte en conflit avec le travail cron. Si j'utilise un .env_setup_rcfichier très simple avec une seule ligne export MY_ENV_VAR=my_env_val:, cela fonctionne réellement. Voir mon article: stackoverflow.com/questions/15557777/…
Peter Lee
63

La configuration de vars a /etc/environmentégalement fonctionné pour moi dans Ubuntu. Depuis le 12.04, les variables dans /etc/environmentsont chargées pour cron.

Augusto Destrero
la source
11
Meilleure réponse, exécutez simplement env >> /etc/environmentet toutes les vars env actuelles sont désormais disponibles dans les tâches CRON.
Savageman
6
cela fonctionne très bien pour moi. surtout parce que je cours dans un Docker Container, donc je ne me soucie pas beaucoup des implications "à l'échelle du système".
Lucas Pottersky
14
@Savageman, c'est comme tuer des mouches avec des bombes à fusion, les enjeux d'un comportement inattendu sont également extrêmement élevés.
Fran Marzoa
2
Soyez prudent: env >> /etc/environmentéchouera s'il y a un signe de hachage dans l'une des variables d'environnement. J'ai eu le plus de mal à dépanner mon application. Il s'est avéré être un mot de passe contenant '#' qui était tronqué à cette étape.
asac
3
Ce devrait être la réponse choisie. Je ne sais pas pourquoi les gens compliquent les choses avec les autres réponses ou avec ces trucs sur env >> / etc / environnement. Clignotez simplement bien éditez etc / environment si vous voulez que ces vars env soient universellement disponibles: mes expériences semblent confirmer que les instructions d'exportation pour les vars env dans / etc / environment sont disponibles pour crontab et aussi pour les utilisateurs. LE PROBLÈME: encore une fois de mes expériences: il semble que ces vars env ne sont pas élargis dans crontab lui-même! ... c'est-à-dire qu'ils ne sont développés que dans les scripts appelés!
Mike Rodent
39

Si vous démarrez les scripts que vous exécutez via cron avec:

#!/bin/bash -l

Ils devraient récupérer vos ~/.bash_profilevariables d'environnement

breizhmg
la source
4
Cette réponse devrait obtenir plus de votes positifs et être simplement la réponse sélectionnée: Très simple et élégant et évite d'innombrables kludges qui nécessiteraient de sauter partout dans le système.
JakeGould
J'aime cette réponse +1. Est-ce que cela pourrait / devrait être utilisé lors de l'exécution rootde crontab? Il n'y a pas de /home/rootdossier sur mon système et je ne vois donc pas comment cela fonctionnerait avec rootcrontab. Des idées?
Seamus
Dans le script lui-même. Que vous exécutez ensuite avec cron normalement.
breizhmg
@Jim voir cet exemple , utilisation d'un fichier exécutable classique (chmod 777) #!/bin/bash. La magie ici est d'ajouter-l
Peter Krauss
22

Développer l'exemple de @carestad, que je trouve plus facile, est d'exécuter le script avec cron et d'avoir 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
16

Pour moi, j'ai dû définir la variable d'environnement pour une application php. Je l'ai récupéré en ajoutant le code suivant à ma crontab.

$ sudo  crontab -e

crontab:

ENVIRONMENT_VAR=production

* * * * * /home/deploy/my_app/cron/cron.doSomethingWonderful.php

et à l'intérieur de doSomethingWonderful.php j'ai pu obtenir la valeur de l'environnement avec:

<?php     
echo $_SERVER['ENVIRONMENT_VAR']; # => "production"

J'espère que ça aide!

karlingen
la source
Ça n'a pas marché pour moi. La variable d'environnement n'était pas disponible dans le script qui a été appelé dans la crontab.
Nikhil
12

Tout ce que vous définissez crontabsera disponible dans les cronjobs, directement et en utilisant les variables dans les scripts.

Utilisez-les dans la définition du cronjob

Vous pouvez configurer de crontabmanière à définir des variables que le cronjob peut utiliser:

$ crontab -l
myvar="hi man"
* * * * * echo "$myvar. date is $(date)" >> /tmp/hello

Maintenant, le fichier /tmp/hellomontre des choses comme:

$ cat /tmp/hello 
hi man. date is Thu May 12 12:10:01 CEST 2016
hi man. date is Thu May 12 12:11:01 CEST 2016

Utilisez-les dans le script exécuté par cronjob

Vous pouvez configurer de crontabsorte qu'il définit des variables que les scripts peuvent ensuite utiliser:

$ crontab -l
myvar="hi man"
* * * * * /bin/bash /tmp/myscript.sh

Et disons que le script /tmp/myscript.shest comme ceci:

echo "Now is $(date). myvar=$myvar" >> /tmp/myoutput.res

Il génère un fichier /tmp/myoutput.resmontrant:

$ cat /tmp/myoutput.res
Now is Thu May 12 12:07:01 CEST 2016. myvar=hi man
Now is Thu May 12 12:08:01 CEST 2016. myvar=hi man
...
fedorqui 'SO arrête de nuire'
la source
7

Développer sur @Robert Brisita vient de se développer, également si vous ne voulez pas configurer toutes les variables du profil dans le script, vous pouvez sélectionner les variables à exporter en haut du script

Dans le fichier crontab -e:

SHELL=/bin/bash

*/1 * * * * /Path/to/script/script.sh

Dans script.sh

#!/bin/bash
export JAVA_HOME=/path/to/jdk

some-other-command
Marcos Pousada
la source
7

Au lieu de

0  *  *  *  *  sh /my/script.sh

Utilisez bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'
Ilya Kharlamov
la source
1
Pourquoi faire cela au lieu de simplement avoir la déclaration Bash en haut du fichier -lcomme ceci #!/bin/bash -l:? Cette autre réponse est simple et élégante.
JakeGould
1
Que faire si j'ai besoin d'exécuter un script perl / python / ruby ​​pas bash? Je ne peux pas ajouter #! / Bin / bash -l en haut d'un script python.
Ilya Kharlamov
"Et si j'ai besoin d'exécuter un script perl / python / ruby ​​pas bash?" C'est suffisant. Mais dans mon esprit, vous pourriez écrire un simple wrapper de script Bash qui appelle ensuite le script Python. Je fais une chose similaire pour les scripts PHP. La raison en est que le verrouillage de processus est tellement meilleur et fiable dans Bash, mais les scripts Bash sont toujours un casse-tête. J'ai donc écrit des trucs en PHP pour les trucs complexes et laissé Bash gérer le reste.
JakeGould
3

J'utilise Oh-my-zshdans mon macbook, j'ai donc essayé beaucoup de choses pour que la tâche crontab s'exécute, mais finalement, ma solution ajoutait .zshrcavant l'exécution de la commande.

*/30 * * * * . $HOME/.zshrc; node /path/for/my_script.js

Cette tâche s'exécute toutes les 30 minutes et utilise le .zshrcprofil pour exécuter ma commande de nœud.

N'oubliez pas d'utiliser le point avant le $HOMEvar.

Stiakov
la source
2

Une autre façon - inspirée de cette réponse - d'injecter des variables est la suivante (exemple fcron):

%daily 00 12 \
    set -a; \
    . /path/to/file/containing/vars; \
    set +a; \
    /path/to/script/using/vars

De help set:

-a Marquer les variables modifiées ou créées pour l'exportation.

L'utilisation de + plutôt que - provoque la désactivation de ces indicateurs.

Donc , tout le reste set -et set +obtient exporté vers envet est alors disponible pour d' autres scripts, etc. Sans utiliser setles variables sont remplacées mais provenant en direct setseulement.

En plus de cela, il est également utile de transmettre des variables lorsqu'un programme nécessite un compte non root pour s'exécuter, mais vous aurez besoin de certaines variables dans l'environnement de cet autre utilisateur. Vous trouverez ci-dessous un exemple de transmission de vars nullmailer pour formater l'en-tête de l'e-mail:

su -s /bin/bash -c "set -a; \
                    . /path/to/nullmailer-vars; \
                    set +a; \
                    /usr/sbin/logcheck" logcheck
Saucier
la source
2

J'ai essayé la plupart des solutions fournies, mais rien n'a fonctionné au début. Il s'avère cependant que ce ne sont pas les solutions qui n'ont pas fonctionné. Apparemment, mon ~/.bashrcfichier commence par le bloc de code suivant:

case $- in
    *i*) ;;
    *) return;;
esac

Il s'agit essentiellement d'un case statementqui vérifie l'ensemble d'options actuel dans le shell actuel pour déterminer que le shell fonctionne de manière interactive. Si le shell s'exécute de manière interactive, il passe ensuite au sourcing du ~/.bashrcfichier. Cependant, dans un shell appelé par cron, la $-variable ne contient pas la ivaleur qui indique l'interactivité. Par conséquent, le ~/.bashrcfichier n'est jamais entièrement approvisionné. Par conséquent, les variables d'environnement n'ont jamais été définies. Si cela vous arrive, n'hésitez pas à commenter le bloc de code comme suit et réessayez:

# case $- in
#     *i*) ;;
#     *) return;;
# esac

J'espère que cela s'avère utile

Abdou
la source
0

Vous pouvez également ajouter votre commande avec envpour injecter des variables d'environnement comme ceci:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
Hussam
la source