cron ignora las variables definidas en ".bashrc" y ".bash_profile"

49

He definido la variable "SHELL" en el archivo / 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 ~]$ 

Además, todos mis scripts en el archivo / etc / crontab se inician bajo el usuario "martin". Sin embargo, /home/martin/.bash_profile (para el shell de inicio de sesión) y /home/martin/.bashrc (para el shell no logging) contienen algunas variables que se ignoran en caso de trabajo cron, pero se usan en caso de que inicie sesión en la máquina. SSH o abra una nueva sesión de bash. ¿Por qué cron ignora esas variables? ¿No está cron simplemente ejecutando "/ usr / local / bin / bash my-script.sh" con permisos para el usuario "martin"?

Martín
fuente
2
Los usuarios de Ubuntu pueden tener en cuenta que el valor predeterminado de Ubuntu .bashrctiene una línea que impide que se ejecute en shells no interactivos.
joeytwiddle

Respuestas:

72

Puede obtener el archivo que desee en la parte superior del script o al comienzo del trabajo para el usuario que está ejecutando el trabajo. El comando "fuente" está integrado. Haría lo mismo si realizara modificaciones en esos archivos para cargar los cambios.

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

o

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

<commands>
gNU.be
fuente
2
Tenga en cuenta que "fuente" podría no funcionar si cron no está utilizando el bashshell. He agregado una respuesta que puede manejar el caso cuando el shell es sh.
Jonathan
23

Porque no es un shell interactivo. Lo mismo sucede cuando abres algunas terminales.

Eche un vistazo a esta pregunta: ¿Qué es el archivo .bashrc? El | Super usuario

Y también en este:

¿Cuál es la diferencia entre .bashrc, .bash_profile y .environment? El | Desbordamiento de pila

Se activan diferentes scripts según si la conexión es un shell de inicio de sesión (o no), un shell interactivo (o no), o ambos.

Si quieres hacer bashrc deberás hacer este cambio:

Cuando Bash se inicia de forma no interactiva, para ejecutar un script de shell, por ejemplo, busca la variable BASH_ENV en el entorno, expande su valor si aparece allí y usa el valor expandido como el nombre de un archivo para leer y ejecutar . Bash se comporta como si se ejecutara el siguiente comando:

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

pero el valor de la variable PATH no se usa para buscar el nombre del archivo.

Como se señaló anteriormente, si se invoca un shell no interactivo con la --loginopción, Bash intenta leer y ejecutar comandos desde los archivos de inicio del shell de inicio de sesión.

Fuente: Bash Startup Files | Manual de referencia de Bash | gnu.org

Dave C
fuente
Entonces, si configuramos BASH_ENV dentro de Cron, los scripts cron bash lo generarán porque cron no es interactivo ni inicia sesión.
CMCDragonkai
12

Es posible que no pueda ejecutar sourcesi shse está utilizando el shell. Esto se puede cambiar agregando la siguiente línea en su crontab:

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

También puede especificar el entorno:

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

o puede usar su local /home/user/.bashrcsi es un trabajo cron de usuario (por ejemplo crontab -e).

Tenga en cuenta que .bash_profilepuede reemplazar .bashrc, si existe.

Crédito: ¿Cómo cambiar cron shell (sh a bash)?

Jonathan
fuente
esto funciona bien también para trabajos programados en la nube de Acquia, que son básicamente trabajos cron. Puedes hacer lo mismo, como:SHELL=/bin/bash && source /home/YOUR_USER_NAME/.bash_profile && sh ....
Alejandro Moreno
1

Otra cosa que podría interferir con el abastecimiento de su .bashrcdesde un trabajo temporal es cualquier verificación que este archivo haga para detectar shells interactivos.

Por ejemplo, en Ubuntu 18.04, el valor predeterminado .bashrcpara un usuario comienza con esto:

# ~/.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

y así el abastecimiento no hará nada útil ya que saldrá inmediatamente.

Francois Marier
fuente
1

Puede invocar bash con la -lopción, así:

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

La -lopción convierte a bash en un shell de inicio de sesión . Por lo tanto, leerá el usuario .bash_profile. No leerá al usuario a .bashrcmenos que se obtenga explícitamente .bash_profile. Esto se debe a que los shells no interactivos no se leen automáticamente .bashrc. Pero no debería necesitar .bashrcun trabajo cron porque .bashrces para configurar cosas útiles para un shell interactivo .

Variaciones:

Si bash está en la RUTA, no hay necesidad de especificar una ruta absoluta:

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

Una optimización sería reemplazar el shell actual mediante el uso de exec:

* * * * * exec bash -l /path/to/script arg1 arg2
Robin A. Meade
fuente
1

bashactúa de manera diferente si es un shell o un lenguaje de programación normal (como perlo python).

Por diseño, las configuraciones en ~/.bash_profile, ~/.bashrcetc. son para que los usuarios establezcan cosas cuando bashdesempeñan el papel de un shell (shell de inicio de sesión, shell interactivo). Piense en el entorno que tiene en un xterm(shell interactivo) o en sshsesiones (shell de inicio de sesión) o en consolas (shell de inicio de sesión).

Por otro lado, bashtambién es un poderoso lenguaje de programación, piense en muchos scripts para administrar servicios systemd, lo que requiere un estilo de trabajo diferente. Por ejemplo, cuando un desarrollador está escribiendo una secuencia de comandos del sistema o un bashprograma, no le gustaría obtener el usuario ~/.bash_profileautomáticamente. Es un programa normal, no un shell. Un programa normal (incluidos los bashprogramas) heredaría naturalmente la configuración del evironement de trabajo actual (shell), pero no la establecería .

Si escribimos un programa para cronin bash, resulta que está escrito en bash; De hecho, podemos escribir en pythono perl, o cualquier otro lenguaje programación, entonces podemos tener una opción para las fuentes de bash's ~/.bash_profile(es decir: el establecimiento de la concha del usuario, que sólo pasa a ser el mismo idioma de su lenguaje de programación):

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

Sin embargo, ¿qué pasa si ese usuario en particular no lo usa bashcomo su shell? Él / ella puede usar zsh, ksh, fish, etc Por lo tanto, esa práctica no es realmente trabajar al escribir el programa para el uso público.

Por lo tanto, puede fuente ~/.bash_profilesi cree que funcionará. Pero, aquí, no se trata de si podemos obtener un archivo, se trata de cómo deberían funcionar las cosas en el sistema: el concepto de diseño . En resumen: deberíamos verlo bashcomo algo que tiene 2 roles: shell y lenguaje de programación . Entonces todo será mucho más fácil de entender.

Bach Lien
fuente
0

Tuve el mismo problema al ejecutar una aplicación de nodo desde cron que usa NVM, para hacer que bash shell lea el archivo .bashrc de cron simplemente invoque el comando bash con la opción de shell interactivo `-l.

p.ej: * * * * * /bin/bash -lc '/home/user/myapp.sh restart'

Si eso no funciona, intente configurar la variable de ruta en crontab

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

Mi manera de lidiar con esto fue esto:

1) Poner mis variables en (al final de) ~/.profile:

myVarInDotProfile="someValue"

2) Crear una secuencia de comandos Bash para mis tareas cron (diarias) ( ~/cronDaily.sh) que contienen mis comandos más un abastecimiento repetitivo de ~/.profle:

source ~/.profile
command ${myVarInDotProfile}/

3) programar la ejecución de mi script desde crontab, para que se ejecute diariamente:

0 0 * * * bash ~/cronDaily.sh

Mi variable no fue ignorada y los comandos se ejecutaron con éxito.


Algunos pueden decir que un abastecimiento tan intenso ~/.profilees problemático. En mi caso particular, no veo por qué es un problema, pero me gustaría considerar crear un archivo dedicado para eso.

En general, puede haber una mejor manera de hacerlo, pero eso es lo que funcionó para mí después de mucho dolor y explica el principio de que a partir de Bash 4.3.46, no puede obtener un archivo crontab.

Arcticooling
fuente