Como posso executar um comando cron com variáveis ​​ambientais existentes?

114

Como posso executar um comando cron com variáveis ​​ambientais existentes?

Se eu estiver em um prompt de shell, posso digitar echo $ORACLE_HOMEe obter um caminho. Esta é uma das minhas variáveis ​​ambientais que é definida na minha ~/.profile. No entanto, parece que ~/.profilenão é carregado de scripts cron e, portanto, meus scripts falham porque a $ORACLE_HOMEvariável não está definida.

Em esta questão o autor menciona a criação de um ~/.cronfileperfil que estabelece variáveis para cron, e então ele faz uma solução alternativa para carregar todos os seus comandos cron em scripts que ele mantém em seu ~/Crondiretório. Um arquivo ~/.cronfileparece uma boa idéia, mas o restante da resposta parece um pouco complicado e eu esperava que alguém pudesse me dizer uma maneira mais fácil de obter o mesmo resultado.

Suponho que, no início dos meus scripts, eu possa adicionar algo parecido, source ~/.profilemas que parece ser redundante.

Então, como posso fazer meus scripts cron carregar as variáveis ​​do meu perfil de shell interativo?

cwd
fonte
Como a adição source ~/.profilea um programa é redundante? Os programas herdam seu ambiente do programa de chamada. Se esse programa de chamada não for o seu shell, como o programa decendente obterá o ambiente que você deseja?
Arcege 21/12
Eu já escrevi minha resposta para uma pergunta semelhante aqui. Ele simplesmente usa su -lpara configurar um ambiente de login normal, incluindo o $ PATH para root ou outro usuário específico.
tasket 14/09

Respostas:

141

No crontab, antes de você comandar, adicione . $HOME/.profile. Por exemplo:

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

Cronnão sabe nada sobre a sua concha; é iniciado pelo sistema, portanto, possui um ambiente mínimo. Se você quer alguma coisa, precisa trazer isso para si mesmo.

Arcege
fonte
14
O que faz o .antes do script? (não sei como eu faria manisso). Por que isso é diferente source?
Cwd
25
O .comando é o comando original para source. Eles são equivalentes dentro do shell e um pouco mais fáceis de digitar, especialmente dentro de um crontab. Para obter mais informações, digite help .ou pesquise ^SHELL BUILTIN COMMANDSna página de manual bashou na parte superior do tipo man zshbuiltins .` . Running informa que o comando é interno.
Arcege
9
Dependendo das distribuições Linux, você pode precisar de mudar .profilepor .bash_profile. Verifique qual .profilearquivo existe no diretório inicial do usuário.
gelado Z
@Arcege Isso não funciona para mim (Fedora Core 21), e presumo que seja porque o nível do shell cai novamente. Em vez disso, o que funciona é se você obtê-lo.
Richard T
3
É provável que, se não estiver funcionando, é porque o SHELL para o script cron não está definido para bash, portanto, não está executando da mesma maneira que você poderia esperar.
22415 Daniel Farrell
40

Outra opção, 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
5
Ao executar em uma AWS Linux AMI, nem me ocorreu que o cron não usaria /bin/bashcomo shell. Fiquei me perguntando por que coisas como cd /path/to/project; source .varsfuncionariam quando eu as digitasse manualmente, mas falhariam ( File not found) quando incluídas em um cronjob. A linha principal para mim foi a configuração, SHELL=/bin/bashpara que eu pudesse realmente usar comandos familiares do bash em cada cronjob. /bin/sh/(o cron shell padrão, aparentemente) é muito limitador.
Hartley Brody
É uma pena que você não possa especificar Arquivos de Ambiente na parte superior do cron, como pode especificar variáveis ​​de ambiente individuais. Systemd tem uma EnvironmentFileunidade de serviço. Pena que o cron não tenha algo parecido.
Radtek
você FORCE todos os scripts a usar / bin / bash em todo o crontab, o que não é uma boa ideia, e também sobre a sua linha cron: * / 1 * * * * $ HOME / cron_job.sh… * / 1 é bom para o que ?!? uma estrela significa que ele será executado a cada 1 meios / minuto será executado a cada minuto, como uma resposta em uma comunidade inteligente este é um pecado desagradável, agora eu acredito que você é muito confuso para dizer o melhor ... desculpe
THESorcerer
1
Isso é chamado de exemplo. Sinta-se à vontade para se ajustar às suas necessidades ou não usá-lo. Cursos diferentes para diferentes pessoas.
Robert Brisita
4
Se $SHELLfor /bin/sh, o sourcecomando não existe. Use em .vez disso.
Melle
18

Outra opção, que eu acho mais fácil, é executar o script com cron e dizer ao bash para efetuar login (portanto, usando /etc/profile.d/...definições de ambiente)

No crontab -earquivo:

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

Qualquer comando após a fonte de .bash_profileterá seu ambiente como se você estivesse conectado.

Artistan
fonte
10

Péssima ideia. A prática geral é definir especificamente todas as variáveis ​​ambientais necessárias em um script que deve ser executado a partir de uma tarefa cron.

fpmurphy
fonte
Concordo com o @fpmurphy, que também garante o ambiente do processo seguro. Se você deseja definir apenas algumas variáveis ​​do cron, pode usar o /usr/bin/envcomando para definir as variáveis ​​e, em seguida, agir como o processo do ambiente para o cronjob.
Nikhil Mulley
daemontools 'envdir vem à mente também.
sr_
6
Sou a favor da segurança, mas talvez eu possa criar um arquivo ~/.cronvarse incluí-lo no perfil e também nos meus scripts cron. Eu não quero codificar variáveis ​​de ambiente em cada um dos scripts que eu executo, porque quando os caminhos mudam os caminhos codificados em cada arquivo não são fáceis de manter. Parece que isso permitiria um local centralizado para as variáveis ​​necessárias e ainda impediria o carregamento de outras variáveis.
Cwd
4

Essa sintaxe definitivamente ajuda você. Eu não entendo a sintaxe, mas funciona. A Oracle usa essa sintaxe, ao implantar o Oracle Configuration Manager no crontab, portanto, acredito que esta é a solução certa.

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

Recentemente, deparei-me com um caso em que eu tinha que executar o cronjob geral como root, mas, ao mesmo tempo, tinha que executar um subcomando como um usuário diferente (o que exigia o fornecimento do ambiente desse usuário). Eu fui com a seguinte abordagem:

# 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

A parte crucial é o argumento -ique está sendo passado para o sudoqual executará o comando fornecido em um shell de login separado (o que, por sua vez, significa que os arquivos de pontos do usuário serão originados).

PS: Note que a usercoluna está disponível apenas no /etc/crontabe os /etc/cron.d/*arquivos.

balu
fonte
1

A solução, que funcionou para mim, é descrita aqui .

Você cria um script de wrapper, que chama . ~/.cronfilee, em seguida, faz o que deseja. Este script é iniciado pelo cron.

Em ~/.cronfilevocê especifica o ambiente para seus trabalhos cron.

weekens
fonte
1

Sim, você pode usar "soluções alternativas conhecidas" (algumas das quais foram listadas). Essa é outra maneira de dizer que todo mundo sabe que é péssimo, embora algumas pessoas se refiram a isso como um "recurso de segurança" porque gastaram pelo menos o máximo de tropeço nessa falha (ure) que você e gostariam de pensar que tempo perdido não era por nada. É o equivalente cron do teclado QWERTY.

Suspeito que o motivo original possa ter sido o desempenho, de modo que os scripts executados uma vez por minuto não gastem tempo para ler scripts rc. Também originalmente o cron não era realmente configurável, então um padrão era realmente a única opção.

Não há segurança adicional por não ter uma configuração ou método simples para que o cron assuma o ambiente do seu shell interativo, em vez de os usuários terem que executar uma ginástica estúpida do shell. Em uma máquina moderna, geralmente não há ganho perceptível de desempenho, a menos que você tenha uma grande quantidade de trabalhos sendo executados a cada minuto.

A cultura Unix falha. Na minha humilde opinião. :-)

Austin S.
fonte
1
"Não há segurança adicional." Isso não é verdade. Dê uma olhada em CVE-2011-1095 , CVE-2008-4304 e CVE-2010-3847 .
A propósito, diminuí a sua resposta. Normalmente, tento evitar o voto negativo das respostas dos recém-chegados, mas a segurança é importante para mim. Por favor, não tome o voto negativo da maneira errada. Além da parte sobre segurança, sua resposta é excelente e merece um voto positivo. Você pode editar sua resposta aqui, se desejar.
Nenhum deles tem a menor coisa a ver com o cron usar um shell com o sinalizador interativo definido. Isso é puro FUD. Infelizmente, não posso diminuir seu voto. Pode parecer uma chama, mas é muito frustrante quando as pessoas pensam que um veículo com três rodas é melhor porque há um problema de segurança para colocar uma quarta roda. Não é. As pessoas andam de triciclo há tanto tempo que esquecem que é possível adicionar uma quarta roda.
26613 Austin S.
Em outras palavras: se qualquer um dos aros extras pretendidos, os outros respondedores sugeridos forem usados, como eles também não terão acesso a nenhum dos buracos mencionados? "* * * * * exec bash -i -c LOCALE = ......."
Austin S.
Isso parece um discurso retórico. Nem vejo onde ele responde à pergunta. Mesmo que a parte de segurança tenha sido removida, @EvanTeitelman, não vejo por que mereceria um voto positivo, pois não responde à pergunta.
Curinga
1

Em vez de definir o perfil, o que me ajudou foi definir o PATH. Alguns dos comandos não estavam disponíveis nos meus scripts cron, pois o PATHé 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

Definir PATHcom o caminho dos comandos me ajudou. Melhor ainda, se você pode usar um modelo e desmembrar mais tarde,

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

Passar variáveis ​​para cada item parece confuso.

Optimus Prime
fonte
-1

Eu coloco . ~/.dbus/session-bus/*no topo do meu script desejado :)

Eric
fonte
1
Bem-vindo à U&L SE. Por favor, expanda sua resposta mais para que beneficie os leitores.
Ramesh