O cron ignora variáveis ​​definidas em ".bashrc" e ".bash_profile"

49

Eu defini a variável "SHELL" no arquivo / etc / crontab:

[martin@martin ~]$ grep SHELL /etc/crontab 
SHELL=/usr/local/bin/bash
[martin@martin ~]$ file /usr/local/bin/bash
/usr/local/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), for FreeBSD 8.0 (800107), stripped
[martin@martin ~]$ 

Além disso, todos os meus scripts no arquivo / etc / crontab são iniciados no usuário "martin". No entanto, /home/martin/.bash_profile (para shell de login) e /home/martin/.bashrc (para shell que não é de log) contêm algumas variáveis ​​que são ignoradas no caso de um trabalho cron, mas são usadas no caso de eu entrar na máquina SSH ou abra uma nova sessão do bash. Por que cron ignora essas variáveis? O cron não está simplesmente executando "/ usr / local / bin / bash my-script.sh" com permissões para o usuário "martin"?

Martin
fonte
2
Os usuários do Ubuntu podem observar que o padrão do Ubuntu .bashrctem uma linha que impede sua execução em shells não interativos.
Joeytwiddle 4/1018

Respostas:

72

Você pode originar o arquivo que deseja na parte superior do script ou no início do trabalho para o usuário que está executando o trabalho. O comando "source" é um built-in. Você faria o mesmo se fizesse edições nesses arquivos para carregar as alterações.

* * * * * source /home/user/.bash_profile; <command>

ou

#!/bin/bash
source /home/user/.bash_profile

<commands>
gNU.be
fonte
2
Observe que "source" pode não funcionar se o cron não estiver usando o bashshell. Eu adicionei uma resposta que pode lidar com o caso quando o shell é sh.
31417 Jonathan
23

Porque não é um shell interativo. O mesmo acontece quando você abre alguns terminais.

Dê uma olhada nesta pergunta: O que é o arquivo .bashrc? | Superusuário

E também neste:

Qual é a diferença entre .bashrc, .bash_profile e .environment? | Estouro de pilha

Scripts diferentes são acionados dependendo se a conexão é um shell de login (ou não), um shell interativo (ou não) ou ambos.

Se você deseja fazer o bashrc, precisará fazer esta alteração:

Quando o Bash é iniciado de maneira não interativa, para executar um script de shell, por exemplo, ele procura a variável BASH_ENV no ambiente, expande seu valor se aparecer lá e usa o valor expandido como o nome de um arquivo para ler e executar . O Bash se comporta como se o seguinte comando tivesse sido executado:

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi 

mas o valor da variável PATH não é usado para procurar o nome do arquivo.

Como observado acima, se um shell não interativo for chamado com a --loginopção, o Bash tentará ler e executar comandos dos arquivos de inicialização do shell de login.

Fonte: Arquivos de inicialização do Bash | Manual de Referência do Bash | gnu.org

Dave C
fonte
Portanto, se definirmos BASH_ENV dentro do Cron, os scripts cron bash fornecerão isso porque o cron não é interativo e não faz login.
CMCDragonkai
12

Talvez você não consiga executar sourcese o shshell estiver sendo usado. Isso pode ser alterado adicionando a seguinte linha no seu crontab:

SHELL=/bin/bash
* * * * * source "/root/.bashrc"; <command>

Você também pode especificar o ambiente:

BASH_ENV="/root/.bashrc"
* * * * * <command>

ou você pode usar o seu local /home/user/.bashrcse for um trabalho cron do usuário (por exemplo crontab -e).

Observe que .bash_profilepode substituir .bashrc, se existir.

Crédito: Como alterar o cron shell (sh para bash)?

Jonathan
fonte
isso funciona bem também para trabalhos agendados do Acquia Cloud, que são basicamente trabalhos cron. Você pode fazer o mesmo, como:SHELL=/bin/bash && source /home/YOUR_USER_NAME/.bash_profile && sh ....
Alejandro Moreno
1

Outra coisa que pode interferir na origem do seu .bashrcde um cronjob é a verificação que esse arquivo faz para detectar shells interativos.

Por exemplo, no Ubuntu 18.04, o padrão .bashrcpara um usuário começa com isso:

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

e, portanto, a terceirização não fará nada de útil, pois será encerrada imediatamente.

François Marier
fonte
1

Você pode invocar o bash com a -lopção, assim:

* * * * * /bin/bash -l /path/to/script arg1 arg2

A -lopção faz do bash um shell de login . Assim, ele lerá o usuário .bash_profile. Ele não lerá o usuário, a .bashrcmenos que seja explicitamente fornecido por .bash_profile. Isso ocorre porque os shells não interativos não são lidos automaticamente .bashrc. Mas você não deve precisar .bashrcde um trabalho cron, pois .bashrcé para definir coisas úteis para um shell interativo .

Variações:

Se o bash estiver no PATH, não será necessário especificar um caminho absoluto:

* * * * * bash -l /path/to/script arg1 arg2

Uma otimização seria substituir o shell atual usando exec:

* * * * * exec bash -l /path/to/script arg1 arg2
Robin A. Meade
fonte
1

bashage de maneira diferente, seja um shell ou uma linguagem de programação normal (como perlou python).

Por design, as configurações em ~/.bash_profile, ~/.bashrcetc. são para que os usuários definam as coisas quando bashdesempenham o papel de um shell (shell de login, shell interativo). Pense no ambiente que você possui em um xterm(shell interativo) ou em sshsessões (shell de login) ou em consoles (shell de login).

Por outro lado, bashtambém é uma poderosa linguagem de programação - pense em muitos scripts para gerenciar serviços systemd- que requer um estilo diferente de trabalho. Por exemplo, quando um desenvolvedor está escrevendo um script do sistema ou um bashprograma, ele / ela não gosta de fornecer o usuário ~/.bash_profileautomaticamente. É um programa normal, não um shell. Um programa normal (incluindo bashprogramas) seria naturalmente herdar as configurações do evironement de trabalho atual (shell), mas não definir -los.

Se escrevermos um programa para cronin bash- ele simplesmente será escrito bash; na verdade, podemos escrever em pythonou perlou qualquer outra programação language- então podemos ter uma opção de fontes bash's ~/.bash_profile(leia-se: a criação de shell do usuário, que só acontece de ser o mesmo idioma de sua linguagem de programação):

[ -f /home/user/.bash_profile ] && . /home/user/.bash_profile

No entanto, e se esse usuário em particular não usar bashcomo seu shell? Ele / ela pode usar zsh, ksh, fish, etc. Então, essa prática não seria realmente trabalhar ao escrever programa para uso público.

Então, você pode pesquisar ~/.bash_profilese acha que funcionará. Mas, aqui, não se trata de saber se somos capazes de obter um arquivo, mas de como as coisas devem funcionar no sistema: o conceito de design . Em resumo: devemos ver bashcomo algo que tem dois papéis: linguagem shell e programação . Então tudo será muito mais fácil de entender.

Bach Lien
fonte
0

Eu tive o mesmo problema ao executar um aplicativo de nó do cron que usa o NVM. Para fazer com que o bash shell leia o arquivo .bashrc do cron, chame o comando bash com a opção de shell interativa `-l.

por exemplo: * * * * * /bin/bash -lc '/home/user/myapp.sh restart'

Se isso não funcionar, tente definir a variável de caminho no crontab

41 7 * * * /bin/bash -lc "PATH=$PATH:/home/user/.nvm/versions/node/v8.10.0/bin && /home/user/script.sh restart "
Shyam Jos
fonte
-1

Meu jeito de lidar com isso era o seguinte:

1) Colocando minhas variáveis ​​(no final de) ~/.profile:

myVarInDotProfile="someValue"

2) Criando um script Bash para minhas tarefas cron (diárias) ( ~/cronDaily.sh) contendo meus comandos, além de fornecimento repetitivo de ~/.profle:

source ~/.profile
command ${myVarInDotProfile}/

3) agendar a execução do meu script a partir crontabda execução diária:

0 0 * * * bash ~/cronDaily.sh

Minha variável não foi ignorada e os comandos foram executados com sucesso.


Alguns podem dizer que esse fornecimento intenso ~/.profileé problemático. No meu caso particular, não vejo por que isso é um problema, mas aconselho a criação de um arquivo dedicado para isso.

Em geral, pode haver uma maneira melhor de fazer isso, mas foi isso que funcionou para mim depois de muita dor e explica o princípio de que, no Bash 4.3.46, você não pode obter um arquivo crontab.

Arcticooling
fonte