Onde posso definir variáveis ​​de ambiente que o crontab usará?


266

Eu tenho um crontab funcionando a cada hora. O usuário que o executa possui uma variável de ambiente .bash_profileque funciona quando o usuário executa o trabalho a partir do terminal; no entanto, obviamente eles não são identificados pelo crontab durante a execução.

Eu tentei colocá-los .profilee, .bashrcmas eles ainda não parecem ser apanhados. Alguém sabe onde eu posso colocar vários ambientes que o crontab pode captar?

Respostas:


88

Faça com que 'cron' execute um script de shell que defina o ambiente antes de executar o comando.

Sempre.

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

Os scripts em ~ / bin / Cron são todos links para um único script, 'runcron', que se parece com:

:       "$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 um padrão de codificação mais antigo - atualmente, eu usaria um '#!' No início.)

O '~ / .cronfile' é uma variação do meu perfil para uso pelo cron - rigorosamente não interativo e sem eco por causa de ser barulhento. Você pode organizar a execução do .profile e assim por diante. (O material REAL_HOME é um artefato do meu ambiente - você pode fingir que é o mesmo que $ HOME.)

Portanto, esse código lê o ambiente apropriado e executa a versão não Cron do comando no meu diretório pessoal. Então, por exemplo, meu comando 'dia da semana' se parece com:

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

# Update ICSCOPE
n.updics

O comando 'diário' é mais simples:

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

246

Você pode definir variáveis ​​de ambiente no próprio crontab ao executar a crontab -epartir da linha de comandos.

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

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

Esse recurso está disponível apenas para determinadas implementações do cron. Atualmente, o Ubuntu e o Debian usam o vixie-cron, o que permite que eles sejam declarados no arquivo crontab (também GNU mcron ).

O Archlinux e o RedHat usam cronie, que não permite que variáveis ​​de ambiente sejam declaradas e lançará erros de sintaxe no cron.log. A solução alternativa pode ser feita por entrada:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"

58
Observe que você não pode usar substituição de variável como no shell, portanto, uma declaração como PATH = / usr / local / bin: $ PATH é interpretada literalmente.
— Zac

8
Eu era capaz de definir as variáveis de ambiente no próprio crontab sob RedHat 4.4.7-3 e cronie-1.4.4-15.el6.x86_64
— de Bruno Lange

7
Você realmente não precisa exportar variáveis ​​se as variáveis ​​forem usadas apenas dentro do comando, apenas adicione-as antes do seu comando. "* * * * * sono 5s; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL"
— vutran 13/11/2015


@BrunoLange você poderia compartilhar como conseguiu configurá-los?
— Newskooler

145

Eu tenho mais uma solução para este problema:

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

Nesse caso, ele selecionará toda a variável de ambiente definida no seu $HOME/.profilearquivo.

Claro $HOME também não está definido, você deve substituí-lo pelo caminho completo do seu $HOME.


Isso funcionou para mim depois de lutar muito para encontrar a resposta, obrigado!
— Vladimir montealegre

5
isso não funcionou para mim até que eu percebi que havia deixado de fora esse período anterior a $ HOME. O que exatamente esse período faz?
— flymike

9
O período é equivalente ao comando "source": tldp.org/LDP/abs/html/special-chars.html#DOTREF
— Jeff W

@ PeterLee alguma coisa mencionada funcionou para você? Eu escrevi isso porque as soluções acima mencionadas não eram eficazes para mim. Se a solução acima mencionada não funcionar, terei que fazer alguma pesquisa para descobrir o motivo. ;-)
— Vishal 22/03

3
Visis @ Na verdade, agora funciona para mim. Eu estava tentando source ~/.bashrc, e acontece que meu .bashrcarquivo está meio que em conflito com o trabalho cron. Se eu usar um .env_setup_rcarquivo muito simples com apenas uma linha export MY_ENV_VAR=my_env_val:, ele realmente funciona. Veja meu post: stackoverflow.com/questions/15557777/...
— Peter Lee

63

Definir vars /etc/environmenttambém funcionou para mim no Ubuntu. A partir de 12.04, as variáveis ​​in /etc/environmentsão carregadas para cron.


11
Melhor resposta, basta executar env >> /etc/environmente agora todos os envios atuais estão disponíveis nos trabalhos do CRON.
— Savageman 16/03/16

6
isso funciona muito bem para mim. especialmente porque estou executando um Docker Container, por isso não me importo muito com implicações de "todo o sistema".
— Lucas Pottersky

14
@ Savageman, que é como matar moscas com bombas de fusão, também os riscos de um comportamento inesperado são extremamente altos.
— Fran Marzoa

2
Cuidado: env >> /etc/environmentfalhará se houver um sinal de hash em uma das variáveis ​​de ambiente. Eu tive mais dificuldade em solucionar meu aplicativo. Acabou sendo uma senha contendo '#' que estava sendo truncada nessa etapa.
— Asac

3
Essa deve ser a resposta escolhida. Não sei por que as pessoas estão complicando as coisas com as outras respostas ou com esse material sobre o env >> / etc / environment. Apenas piscando, edite o etc / environment se você quiser que esses envars estejam disponíveis universalmente: meus experimentos parecem confirmar que as instruções de exportação para env envs no / etc / environment estão disponíveis para o crontab e também para os usuários. O PROBLEMA: novamente a partir de meus experimentos: parece que esses ambientes não são expandidos dentro do próprio crontab! ... ou seja, eles são expandidos apenas nos scripts chamados!
— mike roedor

39

Se você iniciar os scripts que está executando através do cron com:

#!/bin/bash -l

Eles devem pegar suas ~/.bash_profilevariáveis ​​de ambiente


4
Essa resposta deve receber mais votos positivos e ser simplesmente a resposta selecionada: Muito simples e elegante e evita inúmeros discursos que exigiriam pular por todo o sistema.
— JakeGould

Eu gosto desta resposta +1. Isso pode / deve ser usado ao executar rooto crontab? Não existe uma /home/rootpasta no meu sistema e, portanto, não vejo como isso funcionaria com rooto crontab. Ideias?
— Seamus

No próprio script. Que você executa com o cron normalmente.
— breizhmg 25/04

@ Jim veja este exemplo , uso de arquivo executável clássico (chmod 777) #!/bin/bash. A mágica aqui é adicionar-l
— Peter Krauss

22

Expandir o exemplo @carestad, que eu acho mais fácil, é executar o script com cron e ter o ambiente no script.

No arquivo crontab -e:

SHELL=/bin/bash

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

No arquivo cron_job.sh:

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

Qualquer comando após a origem do arquivo .bash_profile terá seu ambiente como se você estivesse conectado.


16

Para mim, eu tive que definir a variável de ambiente para um aplicativo php. Eu o adorei adicionando o seguinte código ao meu crontab.

$ sudo  crontab -e

crontab:

ENVIRONMENT_VAR=production

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

e dentro doSomethingWonderful.php eu poderia obter o valor do ambiente com:

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

Eu espero que isso ajude!


Isso não funcionou para mim. A variável de ambiente não estava disponível no script que foi chamado dentro do crontab.
— 26619 Nikhil

12

Tudo o que você definir crontabestará disponível nos cronjobs, diretamente e usando as variáveis ​​nos scripts.

Use-os na definição do cronjob

Você pode configurar crontabpara que ele defina variáveis ​​que o cronjob pode usar:

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

Agora o arquivo /tmp/hellomostra coisas 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

Use-os no script executado pelo cronjob

Você pode configurar crontabpara que ele defina variáveis ​​que os scripts possam usar:

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

E digamos que o script /tmp/myscript.shé assim:

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

Ele gera um arquivo /tmp/myoutput.resmostrando:

$ 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
...

7

A expansão no @Robert Brisita acabou de expandir, também se você não quiser configurar todas as variáveis ​​do perfil no script, poderá selecionar as variáveis ​​a serem exportadas na parte superior do script

No arquivo crontab -e:

SHELL=/bin/bash

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

Em script.sh

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

some-other-command

7

Ao invés de

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

Use bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'

1
Por que isso, em vez de apenas ter a declaração Bash na parte superior do arquivo, tem o -lseguinte #!/bin/bash -l:? Essa outra resposta é simples e elegante.
— JakeGould

1
E se eu precisar executar um script perl / python / ruby ​​não bash? Não consigo adicionar #! / Bin / bash -l à parte superior de um script python.
— Ilya Kharlamov

"E se eu precisar executar um script perl / python / ruby ​​não bash?" Justo. Mas, na minha opinião, você pode escrever um simples wrapper de script Bash que chama o script Python. Eu faço uma coisa semelhante para scripts PHP. O motivo é que o bloqueio do processo é muito melhor e confiável no Bash, mas o script do Bash ainda é uma dor de cabeça. Então, eu escrevi coisas em PHP para as coisas complexas e deixei o Bash lidar com o resto.
— JakeGould

3

Estou usando Oh-my-zshno meu macbook e tentei várias coisas para executar a tarefa crontab, mas, finalmente, minha solução foi anexar o .zshrcantes do comando ser executado.

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

Esta tarefa é executada a cada 30 minutos e usa .zshrc perfil para executar o comando my node.

Não se esqueça de usar o ponto antes da $HOMEvar.


2

Outra maneira - inspirada por esta resposta - de "injetar" variáveis ​​é a seguinte (exemplo fcron):

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

De help set:

-a Marca variáveis ​​modificadas ou criadas para exportação.

Usar + em vez de - faz com que esses sinalizadores sejam desativados.

Portanto, tudo o que é exportado set -e set +exportado para enve fica disponível para outros scripts, etc. Sem o uso setdas variáveis, é possível obter apenas a fonte set.

Além disso, também é útil passar variáveis ​​quando um programa exige que uma conta não raiz seja executada, mas você precisa de algumas variáveis ​​dentro do ambiente desse outro usuário. Abaixo está um exemplo passando em nullmailer vars para formatar o cabeçalho do email:

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

2

Tentei a maioria das soluções fornecidas, mas nada funcionou no começo. Acontece, porém, que não foram as soluções que falharam no trabalho. Aparentemente, meu ~/.bashrcarquivo começa com o seguinte bloco de código:

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

Isso basicamente é um case statement que verifica o conjunto atual de opções no shell atual para determinar se o shell está sendo executado interativamente. Se o shell estiver executando interativamente, ele passará para a fonte do ~/.bashrcarquivo. No entanto, em um shell invocado por cron, a $-variável não contém o ivalor que indica interatividade. Portanto, o ~/.bashrcarquivo nunca é totalmente adquirido. Como resultado, as variáveis ​​de ambiente nunca foram definidas. Se esse for o seu problema, sinta-se à vontade para comentar o bloco de código da seguinte forma e tente novamente:

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

Espero que isso seja útil


0

Você também pode anexar seu comando envpara injetar variáveis ​​de ambiente da seguinte maneira:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.