Come posso eseguire un comando cron con variabili ambientali esistenti?


114

Come posso eseguire un comando cron con variabili ambientali esistenti?

Se sono al prompt della shell, posso digitare echo $ORACLE_HOMEe ottenere un percorso. Questa è una delle mie variabili ambientali che viene impostata nel mio ~/.profile. Tuttavia, sembra che ~/.profilenon venga caricato dagli script cron e quindi i miei script non riescono perché la $ORACLE_HOMEvariabile non è impostata.

In questa domanda l'autore menziona la creazione di un ~/.cronfileprofilo che imposta le variabili per cron, quindi esegue una soluzione alternativa per caricare tutti i suoi comandi cron negli script che mantiene nella sua ~/Crondirectory. Un file come ~/.cronfilesembra una buona idea, ma il resto della risposta sembra un po 'ingombrante e speravo che qualcuno potesse dirmi un modo più semplice per ottenere lo stesso risultato.

Suppongo che all'inizio dei miei script potrei aggiungere qualcosa del genere, source ~/.profilema sembra che potrebbe essere ridondante.

Quindi, come posso fare in modo che i miei script cron caricino le variabili dal mio profilo della shell interattiva?


Come è source ~/.profileridondante l' aggiunta a un programma? I programmi ereditano il loro ambiente dal programma chiamante. Se quel programma chiamante non è la tua shell, come farà il programma decendente a ottenere l'ambiente che desideri?
Arcege,

Ho già scritto la mia risposta a una domanda simile qui. Utilizza semplicemente su -lper configurare un normale ambiente di accesso incluso $ PATH per l'utente root o per altri utenti specifici.
tasket

Risposte:


141

Nel crontab, prima di comandare, aggiungi . $HOME/.profile. Per esempio:

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

Cronnon sa nulla del tuo guscio; è avviato dal sistema, quindi ha un ambiente minimo. Se vuoi qualcosa, devi averlo portato dentro di te.


14
Cosa fa .prima della sceneggiatura? (non sono sicuro di come lo farei man). Perché è diverso da source?
Cwd

25
Il .comando è il comando originale per source. Sono equivalenti all'interno della shell e un po 'più facili da digitare, specialmente all'interno di un crontab. Per ottenere maggiori informazioni, digita help .o cerca ^SHELL BUILTIN COMMANDSnella pagina man basho nella parte superiore del tipo man zshbuiltins .` . Running ti dirà che il comando è incorporato.
Arcege,

9
A seconda delle distribuzioni Linux, potrebbe essere necessario cambiare .profileda .bash_profile. Controlla quale .profilefile esiste nella home directory dell'utente.
Frosty Z,

@Arcege Questo non funziona per me (Fedora Core 21), e presumo sia perché il livello della shell si abbassa di nuovo. Invece, ciò che funziona è se lo si fonte.
Richard T,

3
È probabile che se non funziona, è perché SHELL per lo script cron non è impostato su bash, quindi non sta eseguendo nello stesso modo in cui ti aspetteresti.
Daniel Farrell,

40

Un'altra opzione, che trovo più semplice, è 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.


5
Durante l'esecuzione su un'AMI Linux AWS, non mi è nemmeno venuto in mente che cron non avrebbe usato /bin/bashcome shell. Continuavo a chiedermi perché cose del genere cd /path/to/project; source .varsfunzionassero quando le scrivevo manualmente ma fallivano ( File not found) se incluse in un cronjob. La linea chiave per me era l'impostazione in SHELL=/bin/bashmodo da poter effettivamente utilizzare i comandi bash familiari in ogni cronjob. /bin/sh/(apparentemente la cron shell di default) è molto limitante.
Hartley Brody,

È un peccato che non sia possibile specificare i file di ambiente nella parte superiore del cron come se fosse possibile specificare singole variabili di ambiente. Systemd ha EnvironmentFileun'unità di servizio. Peccato che cron non abbia qualcosa di simile.
Radtek,

FORZA tutti gli script per usare / bin / bash in tutto crontab, il che non è una buona idea, anche ciò che riguarda la tua cron line: * / 1 * * * * $ HOME / cron_job.sh… * / 1 è buono per COSA ?!? una stella significa che verrà eseguita ogni minuto / 1 significa che verrà eseguita ogni minuto, come risposta in una comunità intelligente questo è un peccato brutto, ora credo che tu sia molto confuso per dire il migliore ... scusate
THESorcerer

1
Questo è ciò che viene chiamato un esempio. Sentiti libero di adattarti alle tue esigenze o di non usarlo affatto. Interessi diversi per gente diversa.
Robert Brisita,

4
In caso $SHELLaffermativo /bin/sh, il sourcecomando non esiste. Usa .invece.
Melle

18

Un'altra opzione, che trovo più semplice, è eseguire lo script con cron e dire a bash di accedere (quindi usando /etc/profile.d/...le definizioni di ambiente)

Nel crontab -efile:

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

Qualsiasi comando dopo la fonte di .bash_profileavrà il tuo ambiente come se avessi effettuato l'accesso.


10

Cattiva idea. La pratica generale è impostare in modo specifico tutte le variabili ambientali richieste in uno script che deve essere eseguito da un cron job.


Sono d'accordo con @fpmurphy, in che modo garantisce anche l'ambiente di processo sicuro. Se si desidera impostare solo poche variabili da cron, è possibile utilizzare il /usr/bin/envcomando per impostare le variabili e quindi agire come processo ambientale per cronjob.
Nikhil Mulley,

mienvdir viene in mente anche il daemontools .
sr_

6
Sono tutto per la sicurezza, ma forse posso creare un file ~/.cronvarse includerlo nel profilo e anche nei miei script cron. Non voglio codificare le variabili ambientali in ciascuno degli script che eseguo perché quando i percorsi cambiano i percorsi codificati in ogni file non sono facili da mantenere. Sembra che consentirebbe un posto centralizzato per le variabili necessarie e impedirebbe comunque il caricamento di altre variabili.
Cwd

4

Questa sintassi ti aiuta sicuramente. Non capisco la sintassi, ma funziona. Oracle utilizza questa sintassi, quando distribuisce Oracle Configuration Manager per crontab, quindi credo che questa sia la soluzione giusta.

0 5 * * * SOME_ENV_VAR=some_value some_command some_parameters

2

Di recente mi sono imbattuto in un caso in cui dovevo eseguire il cronjob generale come root ma, allo stesso tempo, dovevo eseguire un sottocomando come utente diverso (che richiedeva l'approvvigionamento dell'ambiente di quell'utente). Sono andato con il seguente approccio:

# 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 parte cruciale è l'argomento a -icui viene passato sudoche eseguirà il comando dato in una shell di login separata (che a sua volta significa che i dotfile dell'utente verranno forniti).

PS: Si noti che la usercolonna è disponibile solo nei /etc/crontabe dei /etc/cron.d/*file.


1

La soluzione, che ha funzionato per me, è descritta qui .

Si crea uno script wrapper, che chiama . ~/.cronfilee quindi fa le cose che vuoi. Questo script è lanciato da cron.

In ~/.cronfilesi specifica l'ambiente per i lavori cron.


1

Sì, puoi usare "soluzioni alternative ben note" (alcune delle quali sono state elencate). Questo è un altro modo per dire che tutti sanno che è scadente, anche se alcune persone si riferiranno a questa come una "caratteristica di sicurezza" perché hanno speso almeno tanto inciampare su questo fallimento (sì) come hai fatto, e vorrebbero pensare al loro il tempo sprecato non era per nulla. È l'equivalente cron della tastiera QWERTY.

Ho il sospetto che il motivo originale potrebbe essere stato per le prestazioni, in modo che gli script eseguiti una volta al minuto non passino il tempo a leggere gli script rc. Anche originariamente cron non era affatto configurabile, quindi un default era davvero l'unica opzione.

Non vi è alcuna sicurezza aggiuntiva non avendo una semplice configurazione o metodo per fare in modo che cron acquisisca semplicemente l'ambiente della shell interattiva invece che gli utenti debbano eseguire una stupida ginnastica con shell. Su una macchina moderna non vi è generalmente alcun miglioramento percepibile delle prestazioni a meno che non si abbia una grande quantità di lavori in esecuzione ogni minuto.

La cultura Unix fallisce. A mio modesto parere. :-)


1
"Non c'è sicurezza aggiuntiva." Quello non è vero. Dai un'occhiata a CVE-2011-1095 , CVE-2008-4304 e CVE-2010-3847 .

A proposito, ho declassato la tua risposta. Di solito cerco di evitare di sottovalutare le risposte dei nuovi arrivati, ma la sicurezza è importante per me. Per favore, non prendere il downvote nel modo sbagliato. Oltre alla parte relativa alla sicurezza, la tua risposta è eccellente e meriterebbe un voto positivo. Puoi modificare la tua risposta qui se lo desideri.

Nessuno di questi ha la minima cosa a che fare con avere cron che usa una shell con il flag interattivo impostato. Questo è puro FUD. Purtroppo non posso sottovalutare il tuo downvote. Può sembrare una fiamma, ma è molto frustrante quando le persone pensano che un veicolo a tre ruote sia migliore perché c'è un problema di sicurezza per mettere su una quarta ruota. Non lo è. Le persone hanno appena guidato un triciclo per così tanto tempo che hanno dimenticato che è possibile aggiungere una quarta ruota.
Austin S.

Detto in altro modo: se viene utilizzato uno dei cerchi extra previsti che vengono suggeriti dagli altri risponditori, in che modo non possono accedere a nessuno dei fori menzionati? "* * * * * exec bash -i -c LOCALE = ......."
Austin S.

Sembra un rant. Non vedo nemmeno dove risponda alla domanda. Anche se la parte di sicurezza fosse rimossa, @EvanTeitelman, non vedo perché meriterebbe un voto in quanto non risponde alla domanda.
Wildcard il


1

Invece di impostare il profilo, ciò che mi ha aiutato è stato impostare il PATH. Alcuni dei comandi non erano disponibili nei miei script cron poiché PATHsono diversi.

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

L'impostazione PATHcon il percorso dei comandi mi ha aiutato. Ancora meglio se puoi usare un modello e detemplatize in seguito,

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

Passare le variabili a ciascun elemento sembra disordinato.


-1

Metto . ~/.dbus/session-bus/*nella parte superiore del mio copione desiderato :)


1
Benvenuti in U & L SE. Espandi di più la tua risposta in modo che possa essere utile ai lettori.
Ramesh,
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.