
Tenemos un script que se utiliza para sincronizar algunos directorios con una unidad de disco USB. Está configurado para ejecutarse una vez al día, pero a menudo tarda más.
Para asegurarnos de que no se ejecuten varias copias del script al mismo tiempo, verificamos la lista de procesos y, si nuestro script está presente, salimos inmediatamente.
#!/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
El problema es que esta verificación funciona bien cuando se ejecuta mediante sudo y la invocación manual a través de la CLI. Sin embargo, cuando se ejecuta a través de cron, se iniciará independientemente. He probado un par de variaciones diferentes pero todas parecen funcionar.
Esto está en FreeNAS 11.2.
Respuesta1
Un pid
archivo es un enfoque común para evitar ejecuciones múltiples de un script. Se puede utilizar así:
#!/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
¿Dónde sleep 25d
se ejecutará el comando real? recomiendo leer estoentrada en el blogpara obtener una explicación detallada de los diversos métodos para manejar este problema. El guión de arriba está tomado de allí.
Se deben verificar los derechos de acceso del usuario para ejecutar el script tal como se establece en el archivo cron. El script actual también podría no identificar si ya se está ejecutando porque los derechos de acceso no son suficientes. De cualquier manera, usar un archivo pid parece una solución mejor y menos propensa a errores para manejar este problema.
Respuesta2
Se puede hacer mucho más fácil. Crea un archivo de bandera. Al comienzo de su script tal vez 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}
El contenido del archivo de ejecución podría ser el PID del proceso en ejecución. Sería más fácil analizar si hay un proceso en ejecución.
En lugar de
touch ${RUNFILE}
usar
echo $$ >${RUNFILE}