¿Dónde puedo configurar las variables de entorno que usará crontab?

266

Tengo un crontab ejecutándose cada hora. El usuario que lo ejecuta tiene variables de entorno .bash_profileque funcionan cuando el usuario ejecuta el trabajo desde la terminal, sin embargo, obviamente estas no son recogidas por crontab cuando se ejecuta.

He intentado configurarlos .profiley .bashrctodavía no parecen ser recogidos. ¿Alguien sabe dónde puedo poner variables de entorno que crontab puede recoger?

James
fuente

Respuestas:

88

Haga que 'cron' ejecute un script de shell que establece el entorno antes de ejecutar el comando.

Siempre.

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

Los scripts en ~ / bin / Cron son todos enlaces a un solo script, 'runcron', que se ve así:

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

(Escrito usando un estándar de codificación más antiguo; hoy en día, usaría un shebang '#!' Al principio).

El '~ / .cronfile' es una variación de mi perfil para uso de cron, rigurosamente no interactivo y sin eco por el hecho de ser ruidoso. Puede organizar la ejecución del .profile y así sucesivamente. (El material REAL_HOME es un artefacto de mi entorno; puede fingir que es lo mismo que $ HOME).

Entonces, este código lee el entorno apropiado y luego ejecuta la versión del comando que no es Cron desde mi directorio de inicio. Entonces, por ejemplo, mi comando 'día de la semana' se ve así:

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

# Update ICSCOPE
n.updics

El comando 'diario' es más 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
fuente
246

Puede definir variables de entorno en el crontab en sí mismo cuando se ejecuta crontab -edesde la línea de comandos.

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

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

Esta característica solo está disponible para ciertas implementaciones de cron. Ubuntu y Debian actualmente usan vixie-cron que permite que estos se declaren en el archivo crontab (también GNU mcron ).

Archlinux y RedHat usan cronie que no permite que se declaren variables de entorno y arrojará errores de sintaxis en cron.log. La solución se puede hacer por entrada:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"
Carestad
fuente
58
Tenga en cuenta que no puede usar la sustitución de variables como en el shell, por lo que una declaración como PATH = / usr / local / bin: $ PATH se interpreta literalmente.
Zac
8
Pude establecer las variables de entorno en el crontab en RedHat 4.4.7-3 y cronie-1.4.4-15.el6.x86_64
Bruno Lange
77
Realmente no necesita exportar variables si las variables solo se usan dentro del comando, solo colóquelas antes de su comando. "* * * * * dormir 5s; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL"
vutran el
@BrunoLange, ¿podrías compartir cómo pudiste configurarlos?
Newskooler
145

Tengo una solución más para este problema:

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

En este caso, elegirá todas las variables de entorno definidas en su $HOME/.profilearchivo.

Por supuesto, $HOMEtampoco está configurado, debe reemplazarlo con la ruta completa de su $HOME.

Vishal
fuente
Esto funcionó para mí después de luchar mucho para encontrar la respuesta, ¡gracias!
vladimir montealegre
55
esto no funcionó para mí hasta que me di cuenta de que había dejado ese período anterior a $ HOME. ¿Qué hace exactamente ese período?
Flymike
9
El período es equivalente al comando "fuente": tldp.org/LDP/abs/html/special-chars.html#DOTREF
Jeff W
@PeterLee, ¿te ha funcionado algo mencionado? Escribí esto ya que las soluciones mencionadas anteriormente no fueron efectivas para mí. Si la solución mencionada anteriormente no funciona, tendré que investigar un poco para encontrar la razón. ;-)
Vishal
3
@Vishal En realidad, ahora funciona para mí. Estaba tratando de hacerlo source ~/.bashrc, y resulta que mi .bashrcarchivo está en conflicto con el trabajo cron. Si uso un .env_setup_rcarchivo muy simple con solo una línea: export MY_ENV_VAR=my_env_valen realidad funciona. Vea mi publicación: stackoverflow.com/questions/15557777/…
Peter Lee
63

Configurar vars /etc/environmenttambién funcionó para mí en Ubuntu. A partir de 12.04, las variables en /etc/environmentse cargan para cron.

Augusto Destrero
fuente
11
La mejor respuesta, simplemente ejecute env >> /etc/environmenty todos los entornos actuales ya están disponibles en los trabajos de CRON.
Savageman
66
Esto funciona muy bien para mí. especialmente porque me estoy encontrando con un contenedor Docker, así que no me importan mucho las implicaciones de "todo el sistema".
Lucas Pottersky,
14
@Savageman es como matar moscas con bombas de fusión, también lo que está en juego es un comportamiento inesperado.
Fran Marzoa
2
Tenga cuidado: env >> /etc/environmentFALLARÁ si hay un signo hash en una de las variables de entorno. Me costó mucho solucionar problemas de mi aplicación. Resultó ser una contraseña que contenía '#' que se estaba truncando en ese paso.
asac
3
Esta debería ser la respuesta elegida. No sé por qué la gente complica las cosas con las otras respuestas o con estas cosas sobre env >> / etc / environment. Solo parpadee bien edite etc / environment si desea que estos env estén disponibles universalmente: mis experimentos parecen confirmar que las declaraciones de exportación para env vars en / etc / environment están disponibles para crontab y también para los usuarios. EL PROBLEMA: nuevamente de mis experimentos: ¡parece que estos entornos NO SE EXPANDEN dentro del crontab mismo! ... es decir, se expanden solo en los scripts llamados!
Mike roedor
39

Si inicia los scripts que está ejecutando a través de cron con:

#!/bin/bash -l

Deberían recoger ~/.bash_profilelas variables de entorno.

breizhmg
fuente
44
Esta respuesta debería obtener más votos positivos y simplemente ser la respuesta seleccionada: muy simple y elegante y evita innumerables errores que requerirían saltar por todo el sistema.
JakeGould
Me gusta esta respuesta +1. ¿Podría / debería usarse esto cuando se ejecuta rootel crontab? No hay una /home/rootcarpeta en mi sistema, así que no veo cómo funcionaría esto con rootel crontab. Ideas?
Seamus
En el guión mismo. Que luego ejecutas con cron normalmente.
Breizhmg
@ Jim ve este ejemplo , uso de archivos ejecutables clásicos (chmod 777) #!/bin/bash. La magia aquí es agregar-l
Peter Krauss
22

Expandir el ejemplo de @carestad, que me parece más fácil, es ejecutar el script con cron y tener el entorno en el script.

En el archivo crontab -e:

SHELL=/bin/bash

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

En el archivo cron_job.sh:

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

Cualquier comando después de la fuente de .bash_profile tendrá su entorno como si hubiera iniciado sesión.

Robert Brisita
fuente
16

Para mí tuve que establecer la variable de entorno para una aplicación php. Lo reservé agregando el siguiente código a mi crontab.

$ sudo  crontab -e

crontab:

ENVIRONMENT_VAR=production

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

y dentro de doSomethingWonderful.php podría obtener el valor del entorno con:

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

¡Espero que esto ayude!

karlingen
fuente
Esto no funcionó para mí. La variable de entorno no estaba disponible en el script que se invocó dentro del crontab.
Nikhil
12

Lo que establezca crontabestará disponible en los cronjobs, tanto directamente como usando las variables en los scripts.

Úsalos en la definición del cronjob

Puede configurarlo crontabpara que establezca variables que luego el cronjob puede usar:

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

Ahora el archivo /tmp/hellomuestra cosas como:

$ 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

Úsalos en el script ejecutado por cronjob

Puede configurar crontabpara que establezca variables que luego los scripts pueden usar:

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

Y decir guión /tmp/myscript.shes así:

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

Genera un archivo que /tmp/myoutput.resmuestra:

$ 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 'así que deja de dañar'
fuente
7

Expandir en @Robert Brisita se acaba de expandir, también si no desea configurar todas las variables del perfil en el script, puede seleccionar las variables para exportar en la parte superior del script

En el archivo crontab -e:

SHELL=/bin/bash

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

En script.sh

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

some-other-command
Marcos Pousada
fuente
7

En vez de

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

Usa bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'
Ilya Kharlamov
fuente
1
¿Por qué hacer esto en lugar de solo tener la declaración de Bash en la parte superior del archivo tiene el -lsiguiente aspecto #!/bin/bash -l:? Esta otra respuesta es simple y elegante.
JakeGould
1
¿Qué sucede si necesito ejecutar un script perl / python / ruby ​​y no bash? No puedo agregar #! / Bin / bash -l a la parte superior de un script de Python.
Ilya Kharlamov
"¿Qué pasa si necesito ejecutar un script perl / python / ruby ​​no bash?" Lo suficientemente justo. Pero en mi opinión, podría escribir un contenedor de script Bash simple que luego llame al script Python. Hago algo similar para los scripts PHP. La razón es que el bloqueo de procesos es mucho mejor y confiable en Bash, pero las secuencias de comandos de Bash siguen siendo un dolor de cabeza. Así que escribí cosas en PHP para las cosas complejas y dejé que Bash se encargara del resto.
JakeGould
3

Estoy usando Oh-my-zshmi Macbook, así que he intentado muchas cosas para ejecutar la tarea crontab, pero finalmente, mi solución fue anteponer .zshrcel comando anterior a ejecutar.

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

Esta tarea se ejecuta cada 30 minutos y usa el .zshrcperfil para ejecutar mi comando de nodo.

No olvides usar el punto antes de la $HOMEvar.

Stiakov
fuente
2

Otra forma, inspirada por esta respuesta , de "inyectar" variables es la siguiente (ejemplo de fcron):

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

De help set:

-a Marcar variables que se modifican o crean para la exportación.

El uso de + en lugar de - hace que estas banderas se apaguen.

Por lo tanto, todo lo que está en el medio set -y set +se exporta a, envy luego está disponible para otros scripts, etc. Sin usar setlas variables, se obtienen pero viven setsolo.

Aparte de eso, también es útil pasar variables cuando un programa requiere una cuenta no root para ejecutarse, pero necesitaría algunas variables dentro del entorno de ese otro usuario. A continuación se muestra un ejemplo que pasa en vars nullmailer para formatear el encabezado del correo electrónico:

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

Probé la mayoría de las soluciones proporcionadas, pero nada funcionó al principio. Sin embargo, resulta que no fueron las soluciones las que no funcionaron. Aparentemente, mi ~/.bashrcarchivo comienza con el siguiente bloque de código:

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

Básicamente, esto es un case statementque comprueba el conjunto actual de opciones en el shell actual para determinar que el shell se ejecuta de forma interactiva. Si el shell se está ejecutando de forma interactiva, entonces se pasa a la fuente del ~/.bashrcarchivo. Sin embargo, en un shell invocado por cron, la $-variable no contiene el ivalor que indica interactividad. Por lo tanto, el ~/.bashrcarchivo nunca se obtiene completamente. Como resultado, las variables de entorno nunca se configuraron. Si este es su problema, no dude en comentar el bloque de código de la siguiente manera e intente nuevamente:

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

Espero que esto resulte útil

Abdou
fuente
0

También puede anteponer su comando envpara inyectar variables de entorno de esta manera:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
Hussam
fuente