Dove posso impostare le variabili d'ambiente che crontab utilizzerà?


266

Ho un crontab in esecuzione ogni ora. L'utente che lo esegue ha un ambiente senza variazioni nel .bash_profilefunzionamento quando l'utente esegue il lavoro dal terminale, tuttavia, ovviamente, questi non vengono rilevati da crontab quando viene eseguito.

Ho provato a inserirli .profilee .bashrc, tuttavia, non sembrano ancora essere raccolti. Qualcuno sa dove posso mettere le variabili d'ambiente che crontab può raccogliere?

Risposte:


88

Chiedi a "cron" di eseguire uno script shell che imposta l'ambiente prima di eseguire il comando.

Sempre.

#   @(#)$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

Gli script in ~ / bin / Cron sono tutti collegamenti a un singolo script, 'runcron', che assomiglia a:

:       "$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 ${@:+"$@"}

(Scritto usando uno standard di codifica più vecchio, al giorno d'oggi, all'inizio userei uno shebang '#!').

Il '~ / .cronfile' è una variante del mio profilo per l'uso da parte di cron - rigorosamente non interattivo e senza eco per il fatto di essere rumoroso. È possibile organizzare l'esecuzione del file .profile e così via. (Il materiale REAL_HOME è un artefatto del mio ambiente - puoi fingere che sia lo stesso di $ HOME.)

Quindi, questo codice legge l'ambiente appropriato e quindi esegue la versione non Cron del comando dalla mia directory home. Quindi, ad esempio, il mio comando 'giorni feriali' appare come:

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

# Update ICSCOPE
n.updics

Il comando 'giornaliero' è più semplice:

:       "@(#)$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

246

È possibile definire le variabili di ambiente nel crontab stesso quando si esegue crontab -edalla riga di comando.

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

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

Questa funzione è disponibile solo per alcune implementazioni di cron. Ubuntu e Debian attualmente usano vixie-cron che consente di dichiararli nel file crontab (anche GNU mcron ).

Archlinux e RedHat usano cronie che non consente di dichiarare le variabili di ambiente e genererà errori di sintassi in cron.log. La soluzione alternativa può essere eseguita per voce:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"

58
Nota che non puoi usare la sostituzione delle variabili come nella shell, quindi una dichiarazione come PATH = / usr / local / bin: $ PATH viene interpretata letteralmente.
Zac,

8
Sono stato in grado di impostare le variabili di ambiente nel crontab stesso in RedHat 4.4.7-3 e cronie-1.4.4-15.el6.x86_64
Bruno Lange

7
Non è necessario esportare le variabili se le variabili vengono utilizzate solo all'interno del comando, basta anteporle prima del comando. "* * * * * sleep 5s; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL"
vutran


@BrunoLange potresti condividere pelase come sei riuscito a configurarli?
Newskooler,

145

Ho un'altra soluzione per questo problema:

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

In questo caso sceglierà tutte le variabili d'ambiente definite nel tuo $HOME/.profilefile.

Naturalmente $HOMEanche non è impostato, devi sostituirlo con il percorso completo del tuo $HOME.


Questo ha funzionato per me dopo aver lottato molto per trovare la risposta, grazie!
Vladimir Montealegre,

5
questo non funzionava per me fino a quando mi sono reso conto di aver lasciato fuori quel periodo precedente a $ HOME. Cosa fa esattamente quel periodo?
flymike

9
Il periodo equivale al comando "source": tldp.org/LDP/abs/html/special-chars.html#DOTREF
Jeff W

@PeterLee ha funzionato qualcosa per te? Ho scritto questo perché le soluzioni sopra menzionate non erano efficaci per me. Se la soluzione sopra menzionata non funziona, dovrò fare alcune ricerche per trovare il motivo. ;-)
Vishal,

3
@Vishal In realtà, ora funziona per me. Ci stavo provando source ~/.bashrc, e risulta che il mio .bashrcfile è in qualche modo in conflitto con il lavoro cron. Se uso un .env_setup_rcfile molto semplice con una sola riga: export MY_ENV_VAR=my_env_valfunziona davvero. Vedi il mio post: stackoverflow.com/questions/15557777/…
Peter Lee

63

Anche l'impostazione di Vars /etc/environmentha funzionato per me in Ubuntu. A partire da 12.04, le variabili in /etc/environmentsono caricate per cron.


11
La migliore risposta, basta eseguire env >> /etc/environmente tutti gli attuali ambienti sono ora disponibili nei lavori CRON.
Savageman,

6
questo funziona alla grande per me. soprattutto perché sto correndo in un Docker Container, quindi non mi interessa molto delle implicazioni "a livello di sistema".
Lucas Pottersky,

14
@Savageman è come uccidere le mosche con le bombe a fusione, anche la posta in gioco di comportamenti imprevisti è estremamente alta.
Fran Marzoa,

2
ATTENZIONE: env >> /etc/environmentFAIL se c'è un segno hash in una delle variabili di ambiente. Ho avuto difficoltà a risolvere la mia domanda. Si è rivelata una password contenente '#' che veniva troncata in quel passaggio.
asac,

3
Questa dovrebbe essere la risposta scelta. Non so perché le persone stiano complicando le cose con le altre risposte o con queste cose sull'ambiente >> / etc / environment. Basta battere le palpebre per modificare etc / environment se si desidera che queste variabili ambientali siano universalmente disponibili: i miei esperimenti sembrano confermare che le dichiarazioni di esportazione per le variabili env in / etc / environment sono disponibili per crontab e anche per gli utenti. IL PROBLEMA: di nuovo dai miei esperimenti: sembra che questi ambiti NON ESPANSO all'interno di crontab stesso! ... cioè sono espansi solo negli script chiamati!
mike rodent,

39

Se avvii gli script che stai eseguendo tramite cron con:

#!/bin/bash -l

Dovrebbero raccogliere le ~/.bash_profilevariabili di ambiente


4
Questa risposta dovrebbe ottenere più voti ed essere semplicemente la risposta selezionata: molto semplice ed elegante ed evita innumerevoli kludges che richiederebbero di saltare su tutto il sistema.
Jake Gould il

Mi piace questa risposta +1. Potrebbe / dovrebbe essere usato quando si esegue rootcrontab? Non ci sono /home/rootcartelle sul mio sistema e quindi non vedo come questo funzionerebbe con rootcrontab. Idee?
Seamus,

Nella sceneggiatura stessa. Che quindi esegui normalmente con cron.
breizhmg

@Jim vedi questo esempio , usa il classico file eseguibile (chmod 777) #!/bin/bash. La magia qui è aggiungere-l
Peter Krauss

22

Espandere sull'esempio di @carestad, che trovo più facile, è eseguire lo script con cron e avere l'ambiente nello script.

Nel file crontab -e:

SHELL=/bin/bash

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

Nel file cron_job.sh:

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

Qualsiasi comando dopo l'origine di .bash_profile avrà il tuo ambiente come se avessi effettuato l'accesso.


16

Per me ho dovuto impostare la variabile d'ambiente per un'applicazione php. L'ho reslo aggiungendo il seguente codice al mio crontab.

$ sudo  crontab -e

crontab:

ENVIRONMENT_VAR=production

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

e dentro doSomethingWonderful.php ho potuto ottenere il valore ambientale con:

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

Spero che aiuti!


Questo non ha funzionato per me. La variabile d'ambiente non era disponibile nello script invocato all'interno del crontab.
Nikhil,

12

Qualunque cosa tu abbia impostato crontabsarà disponibile nei cronjobs, sia direttamente che usando le variabili negli script.

Usali nella definizione del cronjob

È possibile configurare in crontabmodo da impostare variabili che quindi possono utilizzare cronjob can:

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

Ora il file /tmp/hellomostra cose come:

$ 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

Usali nello script eseguito da cronjob

È possibile configurare in crontabmodo da impostare variabili che quindi gli script possono utilizzare:

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

E dire che lo script /tmp/myscript.shè così:

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

Genera un file che /tmp/myoutput.resmostra:

$ 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
...

7

L'espansione su @Robert Brisita si è appena estesa, anche se non si desidera impostare tutte le variabili del profilo nello script, è possibile selezionare le variabili da esportare nella parte superiore dello script

Nel file crontab -e:

SHELL=/bin/bash

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

In script.sh

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

some-other-command

7

Invece di

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

Usa bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'

1
Perché questo invece di avere solo la dichiarazione Bash nella parte superiore del file ha -lquesto aspetto #!/bin/bash -l:? Quest'altra risposta è semplice ed elegante.
Jake Gould il

1
Cosa succede se devo eseguire uno script perl / python / ruby ​​e non bash? Non riesco ad aggiungere #! / Bin / bash -l all'inizio di uno script Python.
Ilya Kharlamov,

"E se avessi bisogno di eseguire uno script perl / python / ruby ​​non bash?" Giusto. Ma nella mia mente potresti scrivere un semplice wrapper di script Bash che poi chiama lo script Python. Faccio una cosa simile per gli script PHP. Il motivo è che il blocco dei processi è molto meglio e affidabile in Bash, ma gli script di Bash sono ancora un mal di testa. Quindi ho scritto cose in PHP per cose complesse e ho lasciato che Bash gestisse il resto.
Jake Gould,

3

Sto usando Oh-my-zshnel mio macbook, quindi ho provato molte cose per far funzionare l'attività crontab ma alla fine, la mia soluzione stava anteponendo l' .zshrcesecuzione prima del comando.

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

Questa attività viene eseguita ogni 30 minuti e utilizza il .zshrcprofilo per eseguire il comando my node.

Non dimenticare di usare il punto prima del $HOMEvar.


2

Un altro modo - ispirato da questa risposta - di "iniettare" le variabili è il seguente (esempio fcron):

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

Da help set:

-a Contrassegnare le variabili che vengono modificate o create per l'esportazione.

L'uso di + anziché di - fa sì che questi flag vengano disattivati.

Quindi tutto ciò che sta nel mezzo set -e set +viene esportato in enved è quindi disponibile per altri script, ecc. Senza usare setle variabili, provengono ma vivono setsolo.

A parte questo, è anche utile passare le variabili quando un programma richiede l'esecuzione di un account non root ma avresti bisogno di alcune variabili nell'ambiente di quell'altro utente. Di seguito è riportato un esempio che passa nei null nuller per formattare l'intestazione dell'e-mail:

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

2

Ho provato la maggior parte delle soluzioni fornite, ma all'inizio non ha funzionato nulla. Si scopre, tuttavia, che non erano le soluzioni a non funzionare. Apparentemente, il mio ~/.bashrcfile inizia con il seguente blocco di codice:

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

Questo è fondamentalmente uno case statementche controlla l'insieme corrente di opzioni nella shell corrente per determinare che la shell funziona in modo interattivo. Se la shell funziona in modo interattivo, passa alla ricerca del ~/.bashrcfile. Tuttavia, in una shell invocata da cron, la $-variabile non contiene il ivalore che indica l'interattività. Pertanto, il ~/.bashrcfile non viene mai fornito completamente. Di conseguenza, le variabili di ambiente non sono mai state impostate. Se questo è il tuo problema, sentiti libero di commentare il blocco di codice come segue e riprova:

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

Spero che questo risulti utile


0

Puoi anche anteporre il tuo comando envper iniettare le variabili d'ambiente in questo modo:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.