Verifique se o script é iniciado pelo cron, em vez de invocado manualmente

19

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?

    
por daisy 31.08.2012 / 11:07

8 respostas

27

Não estou ciente de que cron faça qualquer coisa com seu ambiente por padrão que possa ser útil aqui, mas há algumas coisas que você pode fazer para obter o efeito desejado.

1) Faça um link físico ou flexível para o arquivo de script, para que, por exemplo, myscript e myscript_via_cron apontem para o mesmo arquivo. Você pode então testar o valor de $0 dentro do script quando quiser condicionalmente executar ou omitir certas partes do código. Coloque o nome apropriado no seu crontab e você está pronto.

2) Adicione uma opção ao script e defina essa opção na invocação do crontab. Por exemplo, adicione uma opção -c , que instrui o script a 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, então você pode simplesmente colocar uma linha como RUN_BY_CRON="TRUE" no seu crontab e verificar seu valor no script.

    
por 31.08.2012 / 11:30
18

Scripts executados a partir do cron não são executados em shells interativos. Também não são scripts de inicialização. A diferenciação é que os shells interativos têm STDIN e STDOUT ligados a um tty.

Método 1: verifique se $- inclui o sinalizador i . i está definido para shells interativos.

case "$-" in
    *i*)
        interactive=1
        ;;
    *)
        not_interactive=1
        ;;
esac

Método 2: a verificação é $PS1 está vazia.

if [ -z "$PS1" ]; then
    not_interactive=1 
else
    interactive=1
fi

referência: link

Método 3: teste seu tty. não é como confiável, mas para tarefas simples do cron você deve estar ok, já que o cron não aloca por padrão um tty em um script.

if [ -t 0 ]; then
    interactive=1
else
    non_interactive=1
fi

Tenha em mente que você pode, no entanto, forçar um shell interativo usando -i , mas você provavelmente estaria ciente de que se estivesse fazendo isso ...

    
por 31.08.2012 / 13:50
6

Primeiro, pegue o PID do cron, então pegue o PID pai do processo atual (PPID) 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 possa ter sido iniciado pelo cron, você poderá percorrer os PIDs pai até chegar a $ CRONPID ou 1 (init PID).

algo como isto, talvez (Não testado-mas-pode-trabalhar < 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=1
done

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 CPID
        for CRONPID in $CRONPIDS ; do
                [ $CRONPID -eq $CPID ] && CRON_IS_PARENT=1
                # we could leave earlier but it's okay like that too
        done
done

# now do whatever you want with the information
if [ "$CRON_IS_PARENT" == "1" ]; then
        CRON_CALL="Y"
else
        CRON_CALL="N"
fi

echo "CRON Call: ${CRON_CALL}"
    
por 31.08.2012 / 11:46
2

Se o seu arquivo de script for chamado por cron e ele contiver um shell na primeira linha, como #!/bin/bash , será necessário encontrar o nome pai-pai para o seu propósito.

1) cron é invocado no momento determinado em 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 comando ps para obter o PID pai do PID pai é:

PPPID='ps h -o ppid= $PPID'

mas precisamos do nome do comando, não do pid, por isso chamamos

P_COMMAND='ps h -o %c $PPPID'

agora só precisamos testar o resultado para "cron"

if [ "$P_COMMAND" == "cron" ]; then
  RUNNING_FROM_CRON=1
fi

Agora você pode testar em qualquer lugar do seu script

if [ "$RUNNING_FROM_CRON" == "1" ]; then
  ## do something when running from cron
else
  ## do something when running from shell
fi

Boa sorte!

    
por 09.09.2014 / 11:31
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 tão longe na árvore de processos quanto desejar.

    
por 29.05.2013 / 19:05
1

Uma solução genérica para a pergunta "é minha saída um terminal ou estou executando a partir de um script" é:

( : > /dev/tty) && dev_tty_good=y || dev_tty_good=n
    
por 24.01.2018 / 10:43
0

Um simples echo $TERM | mail [email protected] no cron mostrou-me que, no Linux e no AIX, o cron parece definir $TERM como 'burro'.

Agora, teoricamente, ainda pode haver terminais burros reais por aí, mas eu suspeito que, para a maioria das ocasiões, isso deve ser suficiente ...

    
por 15.12.2017 / 17:45
0

Não há resposta autoritativa, mas as variáveis prompt ( $PS1 ) e terminal ( $TERM ) são bem decentes aqui. Alguns sistemas configuram TERM=dumb enquanto a maioria deixa vazio, então vamos verificar:

if [ "${TERM:-dumb}$PS1" != "dumb" ]; then
  echo "This is not a cron job"
fi

O código acima substitui a palavra "mudo" quando não há valor para $TERM . Portanto, o fogo condicional quando não houver $TERM ou $TERM é definido como "mudo" ou se a variável $PS1 não estiver vazia.

Eu testei isso no Debian 9 ( TERM= ), CentOS 6.4 & 7.4 ( TERM=dumb ) e FreeBSD 7.3 ( TERM= ).

    
por 22.11.2018 / 00:33