¿Cómo puedo ejecutar un comando cron con variables ambientales existentes?

114

¿Cómo puedo ejecutar un comando cron con variables ambientales existentes?

Si estoy en un indicador de shell, puedo escribir echo $ORACLE_HOMEy obtener una ruta. Esta es una de mis variables ambientales que se establece en mi ~/.profile. Sin embargo, parece que ~/.profileno se carga scripts fron cron y, por lo tanto, mis scripts fallan porque la $ORACLE_HOMEvariable no está configurada.

En esta pregunta, el autor menciona la creación de un ~/.cronfileperfil que configura variables para cron, y luego hace una solución para cargar todos sus comandos cron en los scripts que mantiene en su ~/Crondirectorio. Un archivo como ~/.cronfilesuena como una buena idea, pero el resto de la respuesta parece un poco engorroso y esperaba que alguien pudiera decirme una forma más fácil de obtener el mismo resultado.

Supongo que al comienzo de mis scripts podría agregar algo como, source ~/.profilepero parece que podría ser redundante.

Entonces, ¿cómo puedo hacer que mis scripts cron carguen las variables de mi perfil de shell interactivo?

cwd
fuente
¿Cómo es source ~/.profileredundante agregar a un programa? Los programas heredan su entorno del programa de llamadas. Si ese programa de llamada no es su shell, ¿cómo obtendrá el programa descendiente el entorno que desea?
Arcege
Ya escribí mi respuesta a una pregunta similar aquí. Simplemente se usa su -lpara configurar un entorno de inicio de sesión normal que incluye $ PATH para root u otro usuario específico.
tasket

Respuestas:

141

En el crontab, antes de ordenar, agregue . $HOME/.profile. Por ejemplo:

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

Cronno sabe nada de tu caparazón; es iniciado por el sistema, por lo que tiene un entorno mínimo. Si quieres algo, necesitas que te lo traigan.

Arcege
fuente
14
¿Qué hace el .antes del guión? (No estoy seguro de cómo lo haría man). ¿Por qué es esto diferente de source?
cwd
25
El .comando es el comando original para source. Son equivalentes dentro del shell y un poco más fáciles de escribir, especialmente dentro de un crontab. Para obtener más información, escriba help .o busque ^SHELL BUILTIN COMMANDSen la página de manual para basho en la parte superior del tipo man zshbuiltins .` . Running le indicará que el comando está integrado.
Arcege
99
Dependiendo de las distribuciones de Linux, es posible que deba cambiar .profilepor .bash_profile. Compruebe qué .profilearchivo existe en el directorio de inicio del usuario.
Frosty Z
@Arcege Esto no funciona para mí (Fedora Core 21), y supongo que es porque el nivel de shell vuelve a caer. En cambio, lo que sí funciona es si lo obtiene.
Richard T
3
Es probable que si no funciona, es porque SHELL para el script cron no está configurado para bash, por lo que no se está ejecutando de la misma manera que cabría esperar.
Daniel Farrell
40

Otra opción, 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
55
Cuando se ejecuta en una AMI Linux de AWS, ni siquiera se me ocurrió que cron no estaría usando /bin/bashcomo shell. Seguía preguntándome por qué cosas como cd /path/to/project; source .varsfuncionarían cuando las escribía manualmente pero fallaban ( File not found) cuando se incluían en un cronjob. La línea clave para mí estaba configurada SHELL=/bin/bashpara que realmente pudiera usar comandos bash familiares en cada cronjob. /bin/sh/(el shell cron predeterminado, aparentemente) es muy limitante.
Hartley Brody
Es una pena que no pueda especificar archivos de entorno en la parte superior del cron como puede especificar variables de entorno individuales. Systemd tiene una EnvironmentFileunidad de servicio. Lástima que el cron no tenga algo similar.
radtek
FORZAS todos los scripts para usar / bin / bash en todos los crontab, lo cual no es una buena idea, también lo que se trata de tu línea cron: * / 1 * * * * $ HOME / cron_job.sh ... * / 1 es bueno para QUÉ ?!? una estrella significa que se ejecutará cada minuto / 1 significa que se ejecutará cada minuto, como respuesta en una comunidad inteligente este es un pecado desagradable, ahora creo que estás muy confundido para decir lo mejor ... lo siento
THESorcerer
1
Esto es lo que se llama un ejemplo. Siéntase libre de adaptarse a sus necesidades o no lo use en absoluto. Diferentes estilos para diferentes personas.
Robert Brisita
44
Si $SHELLes así /bin/sh, el sourcecomando no existe. Usar en su .lugar.
Melle
18

Otra opción, que me parece más fácil, es ejecutar el script con cron y decirle a bash que inicie sesión (por lo tanto, usando /etc/profile.d/...definiciones de entorno)

En crontab -earchivo:

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

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

Artistan
fuente
10

Mala idea. La práctica general es establecer específicamente todas las variables ambientales requeridas en un script que se ejecutará desde un trabajo cron.

fpmurphy
fuente
Estoy de acuerdo con @fpmurphy, que también garantiza el entorno seguro del proceso. Si desea establecer solo algunas variables desde cron, puede usar el /usr/bin/envcomando para establecer las variables y luego puede actuar como el proceso de entorno para el cronjob.
Nikhil Mulley
daemontools también meenvdir viene a la mente.
sr_
66
Estoy a favor de la seguridad, pero tal vez pueda crear un archivo ~/.cronvarse incluirlo en el perfil y también en mis scripts cron. No quiero codificar variables ambientales en cada uno de los scripts que ejecuto porque cuando las rutas cambian las rutas codificadas en cada archivo no son fáciles de mantener. Parece que eso permitiría un lugar centralizado para las variables necesarias y aún así evitaría que otras variables se carguen.
cwd
4

Esta sintaxis definitivamente te ayuda. No entiendo la sintaxis, pero funciona. Oracle utiliza esta sintaxis, cuando implementa Oracle Configuration Manager para crontab, por lo tanto, creo que esta es una solución correcta.

0 5 * * * SOME_ENV_VAR=some_value some_command some_parameters
meir
fuente
2

Recientemente me encontré con un caso en el que tenía que ejecutar el cronjob general como root pero, al mismo tiempo, tenía que ejecutar un subcomando como un usuario diferente (lo que requería obtener el entorno de ese usuario). Fui con el siguiente enfoque:

# 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 crucial es el argumento al -ique se le pasa sudoque ejecutará el comando dado en un shell de inicio de sesión separado (lo que a su vez significa que se obtendrán los archivos de puntos del usuario).

PD: Tenga en cuenta que la usercolumna solo está disponible en /etc/crontaby los /etc/cron.d/*archivos.

balu
fuente
1

La solución, que funcionó para mí, se describe aquí .

Crea una secuencia de comandos de envoltura, que llama . ~/.cronfiley luego hace las cosas que desea. Este script es lanzado por cron.

En ~/.cronfileusted especifique el entorno para sus trabajos cron.

weekens
fuente
1

Sí, puede usar "soluciones alternativas bien conocidas" (algunas de las cuales se han enumerado). Esta es otra forma de decir que todo el mundo sabe que es una mierda, aunque algunas personas se referirán a esto como una "característica de seguridad" porque han gastado al menos tanto en tropezar con respecto a este fallo (ure) como usted, y les gustaría pensar que El tiempo perdido no era para nada. Es el equivalente cron del teclado QWERTY.

Sospecho que la razón original puede haber sido el rendimiento, de modo que las secuencias de comandos que se ejecutan una vez por minuto no gastarían el tiempo para leer las secuencias de comandos rc. Además, originalmente cron no era realmente configurable en absoluto, por lo que un valor predeterminado era realmente la única opción.

No hay seguridad adicional al no tener una configuración o método simple para que cron solo tome el entorno de su shell interactivo en lugar de que los usuarios tengan que realizar gimnasia estúpida. En una máquina moderna, generalmente no hay un aumento perceptible del rendimiento a menos que tenga una gran cantidad de trabajos ejecutándose cada minuto.

La cultura Unix falla. En mi humilde opinión. :-)

Austin S.
fuente
1
"No hay seguridad adicional". Eso no es verdad. Eche un vistazo a CVE-2011-1095 , CVE-2008-4304 y CVE-2010-3847 .
Por cierto, rechacé tu respuesta. Por lo general, trato de evitar rechazar las respuestas de los recién llegados pero la seguridad es importante para mí. Por favor, no tome el voto negativo de la manera incorrecta. Además de la parte sobre seguridad, su respuesta es excelente y merecería un voto positivo. Puede editar su respuesta aquí si lo desea.
Ninguno de ellos tiene la menor cosa que ver con hacer que cron use un shell con el conjunto de banderas interactivo. Esto es puro FUD. Lamentablemente, no puedo rechazar tu voto negativo. Esto puede parecer una llama, pero es muy frustrante cuando la gente piensa que un vehículo con tres ruedas es mejor porque hay un problema de seguridad para poner una cuarta rueda. No lo es La gente ha montado un triciclo tanto tiempo que han olvidado que es posible agregar una cuarta rueda.
Austin S.
Dicho de otra manera: si se utiliza alguno de los aros adicionales previstos por los otros respondedores sugeridos, ¿cómo no obtienen acceso a ninguno de los agujeros que usted menciona? "* * * * * ejecutivo bash -i -c LOCALE = ......."
Austin S.
Esto se lee como una diatriba. Ni siquiera veo dónde responde la pregunta en absoluto. Incluso si se eliminó la parte de seguridad, @EvanTeitelman, no veo por qué merecería un voto positivo ya que no responde la pregunta.
Comodín
1

En lugar de configurar el perfil, lo que me ayudó fue configurar el PATH. Algunos de los comandos no estaban disponibles en mis scripts cron, ya que PATHes diferente.

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

Establecer PATHcon la ruta de comandos me ayudó. Aún mejor si puedes usar una plantilla y detemplatizar después,

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

Pasar variables a cada elemento parece desordenado.

Optimus Prime
fuente
-1

Puse . ~/.dbus/session-bus/*en la parte superior de mi script deseado :)

Eric
fuente
1
Bienvenido a U & L SE. Expanda más su respuesta para que beneficie a los lectores.
Ramesh