
Temos um script usado para sincronizar alguns diretórios com uma unidade de disco USB. Ele está configurado para ser executado uma vez por dia, mas geralmente leva mais tempo do que isso.
Para garantir que várias cópias do script não sejam executadas ao mesmo tempo, verificamos a lista de processos e se nosso script estiver presente, saímos imediatamente.
#!/bin/bash
#check if we are already running
running=$(ps aux | /usr/bin/grep -i "usb_sync" | /usr/bin/grep -v grep | /usr/bin/grep -c bash)
echo "usb_sync $running" >/opt/local/backup/usb_sync_log
#If we are, the quit
if [ $running -gt 1 ] ; then
exit 0
fi
O problema é que essa verificação funciona bem ao ser executada via sudo e invocação manual por meio da CLI. No entanto, quando executado pelo cron, ele será iniciado de qualquer maneira. Eu tentei algumas variações diferentes, mas todas parecem funcionar.
Isso está no FreeNAS 11.2.
Responder1
Um pid
arquivo é uma abordagem comum para evitar múltiplas execuções de um script. Pode ser usado assim:
#!/bin/bash
PIDFILE=/home/vagrant/forever.pid
if [ -f $PIDFILE ]
then
PID=$(cat $PIDFILE)
ps -p $PID > /dev/null 2>&1
if [ $? -eq 0 ]
then
echo "Process already running"
exit 1
else
## Process not found assume not running
echo $$ > $PIDFILE
if [ $? -ne 0 ]
then
echo "Could not create PID file"
exit 1
fi
fi
else
echo $$ > $PIDFILE
if [ $? -ne 0 ]
then
echo "Could not create PID file"
exit 1
fi
fi
sleep 25d
rm $PIDFILE
Onde sleep 25d
está o comando real a ser executado. Eu recomendo ler issopostagem no blogpara uma explicação detalhada dos vários métodos para lidar com esse problema. O script acima foi retirado daí.
Os direitos de acesso do usuário para executar o script conforme definido no arquivo cron devem ser verificados. O script atual também pode simplesmente não conseguir identificar se o script já está em execução porque os direitos de acesso não são suficientes. De qualquer forma, usar um arquivo pid parece uma solução melhor e menos propensa a erros para lidar com esse problema.
Responder2
Pode ser feito muito mais fácil. Crie um arquivo de sinalização. No início do seu script, talvez use:
## Basic config
SCRIPTNAME=$(basename "$0")
RUNFILE="${SCRIPTNAME}.run"
# 25h in seconds adjust to your needs.
MAX_AGE=90000
# check for running process
if [ -f "$RUNFILE" ]; then
echo "process still running - exit"
if [ $(( $(date +%s) - $(date +%s --reference $RUNFILE) )) -gt ${MAX_AGE} ]; then
rm $RUNFILE;
else
exit
fi
fi
touch $RUNFILE
<your code>
rm ${RUNFILE}
O conteúdo do runfile pode ser o PID do processo em execução. Seria mais fácil analisar se há um processo em execução.
Em vez de
touch ${RUNFILE}
usar
echo $$ >${RUNFILE}