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?

James
fonte

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
Jonathan Leffler
fonte
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"
carestad
fonte
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.

Vishal
fonte
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.

Augusto Destrero
fonte
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

breizhmg
fonte
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.

Robert Brisita
fonte
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!

karlingen
fonte
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
...
fedorqui 'Então pare de prejudicar'
fonte
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
Marcos Pousada
fonte
7

Ao invés de

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

Use bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'
Ilya Kharlamov
fonte
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.

Stiakov
fonte
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
Saucier
fonte
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

Abdou
fonte
0

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

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