Verifique se o script é iniciado pelo cron, em vez de ser chamado manualmente
23
Existe alguma variável que o cron define quando executa um programa? Se o script for executado pelo cron, eu gostaria de pular algumas partes; caso contrário, invoque essas partes.
Como posso saber se o script Bash é iniciado pelo cron?
@terdon: provavelmente porque psestá bastante mal documentado (especialmente a versão do Linux que suporta vários estilos de sintaxe) e a página de manual é ainda mais densa e enigmática do que a maioria das ferramentas. Eu suspeito que a maioria das pessoas nem percebe o quão útil e versátil uma ferramenta pspode ser.
cas
Respostas:
31
Não sei que cron, por padrão, qualquer coisa que faça em seu ambiente possa ser útil aqui, mas há algumas coisas que você pode fazer para obter o efeito desejado.
1) Faça um link duro ou mole para o arquivo de script, de modo que, por exemplo, myscripte myscript_via_cronapontam para o mesmo arquivo. Em seguida, você pode testar o valor de $0dentro do script quando desejar executar ou omitir condicionalmente certas partes do código. Coloque o nome apropriado no seu crontab e pronto.
2) Adicione uma opção ao script e defina essa opção na chamada do crontab. Por exemplo, adicione uma opção -cque diga ao script para executar ou omitir as partes apropriadas do código e adicione -cao nome do comando no seu crontab.
E, é claro, o cron pode definir variáveis de ambiente arbitrárias, para que você possa colocar uma linha como RUN_BY_CRON="TRUE"no seu crontab e verificar seu valor no seu script.
a resposta por cas está funcionando muito bem e pode ser usado para qualquer outra coisa também
Deian
19
Os scripts executados a partir do cron não são executados em shells interativos. Nem os scripts de inicialização. A diferenciação é que os shells interativos têm STDIN e STDOUT anexados a um tty.
Método 1: verifique se $-inclui o isinalizador. iestá definido para conchas interativas.
Método 3: teste seu tty. não é tão confiável, mas para tarefas simples do cron, você deve estar bem, pois o cron não aloca um tty por padrão para um script.
Observe que o comando $ PS1 não funciona ao verificar se o script foi iniciado pelo systemd ou não. o $ - um faz
mveroone
1
Seu link da Universidade de Winnipeg está quebrado.
WinEunuuchs2Unix 31/12/16
1
@TimKennedy De nada .... de Edmonton :)
WinEunuuchs2Unix
'case "$ -" in' não parece funcionar em scripts bash.
Hobadee 17/05/19
@ Hobadee - todos os bashque tenho acesso têm $ -, assim como dashe ksh. até as conchas restritas no Solaris o possuem. Qual plataforma você está tentando usá-lo onde não está funcionando? O que case "$-" in *i*) echo true ;; *) echo false ;; esacte mostra?
Tim Kennedy
7
Primeiro, obtenha o PID do cron, obtenha o PID pai (PPID) pai do processo atual e compare-os:
CRONPID=$(ps ho %p -C cron)
PPID=$(ps ho %P -p $$)if[ $CRONPID -eq $PPID ];then echo Cron is our parent.;fi
Se o seu script for iniciado por outro processo que pode ter sido iniciado pelo cron, você poderá percorrer os PIDs principais até chegar a $ CRONPID ou 1 (PID do init).
algo assim, talvez (Não testado, mas pode funcionar <TM>):
PPID=$$ # start from current PID
CRON_IS_PARENT=0
CRONPID=$(ps ho %p -C cron)while[ $CRON_IS_PARENT -ne 1]&&[ $PPID -ne 1];do
PPID=$(ps ho %P -p $PPID)[ $CRONPID -eq $PPID ]&& CRON_IS_PARENT=1done
De Deian: Esta é uma versão testada no RedHat Linux
# start from current PID
MYPID=$$
CRON_IS_PARENT=0# this might return a list of multiple PIDs
CRONPIDS=$(ps ho %p -C crond)
CPID=$MYPID
while[ $CRON_IS_PARENT -ne 1]&&[ $CPID -ne 1];do
CPID_STR=$(ps ho %P -p $CPID)# the ParentPID came up as a string with leading spaces# this will convert it to int
CPID=$(($CPID_STR))# now loop the CRON PIDs and compare them with the CPIDfor CRONPID in $CRONPIDS ;do[ $CRONPID -eq $CPID ]&& CRON_IS_PARENT=1# we could leave earlier but it's okay like that toodonedone# now do whatever you want with the informationif["$CRON_IS_PARENT"=="1"];then
CRON_CALL="Y"else
CRON_CALL="N"fi
echo "CRON Call: ${CRON_CALL}"
No Solaris, o cron inicia um shell e o shell executa o script, que inicia outro shell. Portanto, o pid pai no script não é o pid do cron.
ceving 15/12/16
4
Se o seu arquivo de script for chamado crone contiver um shell na primeira linha, #!/bin/bashvocê precisará encontrar o nome pai-pai para seu propósito.
1) croné invocado em um determinado momento no seu crontab, executando um shell 2) shell executa seu script 3) seu script está sendo executado
O PID pai está disponível no bash como variável $PPID. O pscomando para obter o PID pai do PID pai é:
PPPID=`ps h -o ppid= $PPID`
mas precisamos do nome do comando, não do pid, então chamamos
P_COMMAND=`ps h -o %c $PPPID`
agora só precisamos testar o resultado para "cron"
Isso funciona apenas para o Linux ps. Para MacOS (assim como Linux, talvez também * BSD), você pode usar o seguinte P_COMMAND:P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
mdd 11/11
1
Funciona no FreeBSD ou no Linux:
if["Z$(ps o comm="" -p $(ps o ppid="" -p $$))"=="Zcron"-o \
"Z$(ps o comm="" -p $(ps o ppid="" -p $(ps o ppid="" -p $$)))"=="Zcron"]then
echo "Called from cron"else
echo "Not called from cron"fi
Você pode ir até a árvore do processo conforme desejar.
Não há resposta autorizada, mas as variáveis prompt ( $PS1) e terminal ( $TERM) são bastante decentes aqui. Alguns sistemas configurados TERM=dumbenquanto a maioria o deixa vazio, portanto, basta verificar:
if["${TERM:-dumb}$PS1"!="dumb"];then
echo "This is not a cron job"fi
O código acima substitui a palavra "burro" quando não há valor para $TERM. Portanto, o condicional é acionado quando não existe $TERMou $TERMestá definido como "burro" ou se a $PS1variável não estiver vazia.
Eu testei isso no Debian 9 ( TERM=), CentOS 6.4 e 7.4 ( TERM=dumb) e FreeBSD 7.3 ( TERM=).
ps
?ps
está bastante mal documentado (especialmente a versão do Linux que suporta vários estilos de sintaxe) e a página de manual é ainda mais densa e enigmática do que a maioria das ferramentas. Eu suspeito que a maioria das pessoas nem percebe o quão útil e versátil uma ferramentaps
pode ser.Respostas:
Não sei que
cron
, por padrão, qualquer coisa que faça em seu ambiente possa ser útil aqui, mas há algumas coisas que você pode fazer para obter o efeito desejado.1) Faça um link duro ou mole para o arquivo de script, de modo que, por exemplo,
myscript
emyscript_via_cron
apontam para o mesmo arquivo. Em seguida, você pode testar o valor de$0
dentro do script quando desejar executar ou omitir condicionalmente certas partes do código. Coloque o nome apropriado no seu crontab e pronto.2) Adicione uma opção ao script e defina essa opção na chamada do crontab. Por exemplo, adicione uma opção
-c
que diga ao script para executar ou omitir as partes apropriadas do código e adicione-c
ao nome do comando no seu crontab.E, é claro, o cron pode definir variáveis de ambiente arbitrárias, para que você possa colocar uma linha como
RUN_BY_CRON="TRUE"
no seu crontab e verificar seu valor no seu script.fonte
Os scripts executados a partir do cron não são executados em shells interativos. Nem os scripts de inicialização. A diferenciação é que os shells interativos têm STDIN e STDOUT anexados a um tty.
Método 1: verifique se
$-
inclui oi
sinalizador.i
está definido para conchas interativas.Método 2: verifique se
$PS1
está vazio.referência: http://techdoc.kvindesland.no/linux/gnubooks/bash/bashref_54.html
Método 3: teste seu tty. não é tão confiável, mas para tarefas simples do cron, você deve estar bem, pois o cron não aloca um tty por padrão para um script.
No entanto, lembre-se de que você pode forçar um shell interativo
-i
, mas provavelmente saberia se estivesse fazendo isso ...fonte
bash
que tenho acesso têm $ -, assim comodash
eksh
. até as conchas restritas no Solaris o possuem. Qual plataforma você está tentando usá-lo onde não está funcionando? O quecase "$-" in *i*) echo true ;; *) echo false ;; esac
te mostra?Primeiro, obtenha o PID do cron, obtenha o PID pai (PPID) pai do processo atual e compare-os:
Se o seu script for iniciado por outro processo que pode ter sido iniciado pelo cron, você poderá percorrer os PIDs principais até chegar a $ CRONPID ou 1 (PID do init).
algo assim, talvez (Não testado, mas pode funcionar <TM>):
De Deian: Esta é uma versão testada no RedHat Linux
fonte
Se o seu arquivo de script for chamado
cron
e contiver um shell na primeira linha,#!/bin/bash
você precisará encontrar o nome pai-pai para seu propósito.1)
cron
é invocado em um determinado momento no seucrontab
, executando um shell 2) shell executa seu script 3) seu script está sendo executadoO PID pai está disponível no bash como variável
$PPID
. Ops
comando para obter o PID pai do PID pai é:mas precisamos do nome do comando, não do pid, então chamamos
agora só precisamos testar o resultado para "cron"
Agora você pode testar em qualquer lugar do seu script
Boa sorte!
fonte
P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
Funciona no FreeBSD ou no Linux:
Você pode ir até a árvore do processo conforme desejar.
fonte
Uma solução genérica para a pergunta "é minha saída de um terminal ou estou executando a partir de um script" é:
fonte
Um simples
echo $TERM | mail [email protected]
no cron me mostrou que, no Linux e no AIX, o cron parece definido$TERM
como 'burro'.Agora, teoricamente, ainda pode haver terminais burros de verdade, mas suspeito que, na maioria das ocasiões, isso seja suficiente ...
fonte
Não há resposta autorizada, mas as variáveis prompt (
$PS1
) e terminal ($TERM
) são bastante decentes aqui. Alguns sistemas configuradosTERM=dumb
enquanto a maioria o deixa vazio, portanto, basta verificar:O código acima substitui a palavra "burro" quando não há valor para
$TERM
. Portanto, o condicional é acionado quando não existe$TERM
ou$TERM
está definido como "burro" ou se a$PS1
variável não estiver vazia.Eu testei isso no Debian 9 (
TERM=
), CentOS 6.4 e 7.4 (TERM=dumb
) e FreeBSD 7.3 (TERM=
).fonte