cron ignora le variabili definite in ".bashrc" e ".bash_profile"


49

Ho definito la variabile "SHELL" nel file / etc / crontab:

[martin@martin ~]$ grep SHELL /etc/crontab 
SHELL=/usr/local/bin/bash
[martin@martin ~]$ file /usr/local/bin/bash
/usr/local/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), for FreeBSD 8.0 (800107), stripped
[martin@martin ~]$ 

Inoltre, tutti i miei script nel file / etc / crontab vengono avviati sotto l'utente "martin". Tuttavia /home/martin/.bash_profile (per la shell di login) e /home/martin/.bashrc (per la shell non di log) contengono alcune variabili che vengono ignorate in caso di cron job, ma vengono utilizzate nel caso in cui accedo a machine over SSH o apri una nuova sessione bash. Perché cron ignora quelle variabili? Cron non sta semplicemente eseguendo "/ usr / local / bin / bash my-script.sh" con le autorizzazioni per l'utente "martin"?


2
Agli utenti di Ubuntu potrebbe piacere notare che l'impostazione predefinita di Ubuntu .bashrcha una linea che ne impedisce l'esecuzione in shell non interattive.
joeytwiddle,

Risposte:


72

È possibile eseguire il sorgente del file desiderato nella parte superiore dello script o all'inizio del lavoro per l'utente che sta eseguendo il lavoro. Il comando "source" è integrato. Faresti la stessa cosa se modifichi questi file per caricare le modifiche.

* * * * * source /home/user/.bash_profile; <command>

o

#!/bin/bash
source /home/user/.bash_profile

<commands>

2
Nota che "source" potrebbe non funzionare se cron non sta usando la bashshell. Ho aggiunto una risposta che può gestire il caso quando lo è la shell sh.
Jonathan,


23

Perché non è una shell interattiva. Lo stesso succede quando si aprono alcuni terminali.

Dai un'occhiata a questa domanda: qual è il file .bashrc? | Super utente

E anche a questo:

Qual è la differenza tra .bashrc, .bash_profile e .environment? | Stack Overflow

Script diversi si attivano a seconda che la connessione sia una shell di login (o meno), una shell interattiva (o meno) o entrambe.

Se vuoi fare bashrc dovrai apportare questa modifica:

Quando Bash viene avviato in modo non interattivo, ad esempio per eseguire uno script di shell, cerca la variabile BASH_ENV nell'ambiente, espande il suo valore se appare lì e utilizza il valore espanso come nome di un file per leggere ed eseguire . Bash si comporta come se fosse eseguito il seguente comando:

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi 

ma il valore della variabile PATH non viene utilizzato per cercare il nome del file.

Come notato sopra, se viene invocata una shell non interattiva con l' --loginopzione, Bash tenta di leggere ed eseguire i comandi dai file di avvio della shell di accesso.

Fonte: file di avvio di Bash | Manuale di riferimento di Bash | gnu.org


Quindi, se impostiamo BASH_ENV all'interno di Cron, gli script cron bash lo genereranno perché cron non è interattivo e non effettua il login.
CMCDragonkai,

13

Potrebbe non essere possibile eseguire sourcese shsi utilizza la shell. Questo può essere modificato aggiungendo la seguente riga nel tuo crontab:

SHELL=/bin/bash
* * * * * source "/root/.bashrc"; <command>

Puoi anche specificare l'ambiente:

BASH_ENV="/root/.bashrc"
* * * * * <command>

oppure puoi usare il tuo locale /home/user/.bashrcse si tratta di un lavoro cron utente (ad es crontab -e.).

Si noti che .bash_profilepuò sostituire .bashrc, se esiste.

Credito: come cambiare cron shell (da sh a bash)?


questo funziona bene anche per i lavori pianificati Acquia Cloud, che sono fondamentalmente lavori cron. Puoi fare lo stesso, come:SHELL=/bin/bash && source /home/YOUR_USER_NAME/.bash_profile && sh ....
Alejandro Moreno il

1

Qualcos'altro che potrebbe interferire con l'approvvigionamento del tuo .bashrcda un cronjob è qualsiasi controllo che questo file fa per rilevare shell interattive.

Ad esempio, su Ubuntu 18.04, l'impostazione predefinita .bashrcper un utente inizia con questo:

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

e quindi approvvigionamento non farà nulla di utile poiché uscirà immediatamente.


1

Puoi invocare bash con l' -lopzione, in questo modo:

* * * * * /bin/bash -l /path/to/script arg1 arg2

L' -lopzione rende bash una shell di login . Pertanto, leggerà l'utente .bash_profile. Non leggerà l'utente a .bashrcmeno che non sia stato esplicitamente fornito da .bash_profile. Questo perché le shell non interattive non vengono lette automaticamente .bashrc. Ma non dovresti aver bisogno .bashrcdi un lavoro cron perché .bashrcserve per impostare cose utili per una shell interattiva .

variazioni:

Se bash è sul PERCORSO, non è necessario specificare un percorso assoluto:

* * * * * bash -l /path/to/script arg1 arg2

Un'ottimizzazione sarebbe quella di sostituire la shell corrente usando exec:

* * * * * exec bash -l /path/to/script arg1 arg2

1

bashagisce diversamente se si tratta di una shell o di un normale linguaggio di programmazione (come perlo python).

In base alla progettazione, le impostazioni in ~/.bash_profile, ~/.bashrcecc. Consentono agli utenti di impostare le cose quando bashsvolge il ruolo di shell (shell di login, shell interrattiva). Pensa all'ambiente che hai in una xterm(shell interattiva) o nelle sshsessioni (shell di accesso) o nelle console (shell di accesso).

D'altra parte, bashc'è anche un potente linguaggio di programmazione, che pensa a molti script per la gestione dei servizi systemd, che richiede un diverso stile di lavoro. Ad esempio, quando uno sviluppatore sta scrivendo uno script di sistema o un bashprogramma, non gli piace procurarsi ~/.bash_profileautomaticamente l'utente . È un programma normale, non una shell. Un normale programma (compresi i bashprogrammi) erediterebbe naturalmente le impostazioni dall'attuale funzionamento (shell), ma non le imposta .

Se scriviamo un programma per cronin bash- sembra essere scritto bash; infatti, siamo in grado di scrivere in pythono di perlo di qualsiasi altra programmazione Lingua- allora possiamo avere la possibilità di fonti bashs' ~/.bash_profile(leggi: l'impostazione della shell dell'utente, che sembra appena essere la stessa lingua del linguaggio di programmazione):

[ -f /home/user/.bash_profile ] && . /home/user/.bash_profile

Tuttavia, cosa succede se quel particolare utente non usa bashcome shell? Lui / lei può utilizzare zsh, ksh, fish, ecc Quindi, che la pratica avrebbe in realtà non funziona quando la scrittura del programma per uso pubblico.

Quindi, puoi procurarti ~/.bash_profilese pensi che funzionerà. Ma, qui, non si tratta se siamo in grado di eseguire il source di un file, si tratta di come le cose dovrebbero funzionare nel sistema: il concetto di design . In breve: dovremmo vedere bashcome qualcosa che ha 2 ruoli: shell e linguaggio di programmazione . Quindi tutto sarà molto più facile da capire.


0

Ho avuto lo stesso problema nell'esecuzione di un'applicazione nodo da cron che utilizza NVM, per fare in modo che shell bash legga il file .bashrc da cron basta invocare il comando bash con l'opzione shell interattiva `-l.

per esempio: * * * * * /bin/bash -lc '/home/user/myapp.sh restart'

Se non funziona, prova a impostare la variabile path in crontab

41 7 * * * /bin/bash -lc "PATH=$PATH:/home/user/.nvm/versions/node/v8.10.0/bin && /home/user/script.sh restart "

-1

Il mio modo di affrontarlo era questo:

1) Mettere le mie variabili in (fine di) ~/.profile:

myVarInDotProfile="someValue"

2) Creazione di uno script Bash per le mie attività (giornaliere) di cron ( ~/cronDaily.sh) contenente i miei comandi e l'approvvigionamento ripetitivo di ~/.profle:

source ~/.profile
command ${myVarInDotProfile}/

3) programmare l'esecuzione del mio script da crontab, per l'esecuzione giornaliera:

0 0 * * * bash ~/cronDaily.sh

La mia variabile non è stata ignorata e i comandi sono stati eseguiti correttamente.


Alcuni potrebbero dire che un approvvigionamento così intenso di ~/.profilesia problematico. Nel mio caso particolare non vedo perché sia ​​un problema, ma consiglierei di prendere in considerazione la creazione di un file dedicato per questo.

In generale, potrebbe esserci un modo migliore per farlo, ma questo è ciò che ha funzionato per me dopo un sacco di dolore e spiega il principio che a partire da Bash 4.3.46, non è possibile ottenere un file da crontab.

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.