2011-01-22 12 views
12

Duplicar posibles:
Quick-and-dirty way to ensure only one instance of a shell script is running at a timeShell script: Asegúrese de que la secuencia de comandos no se ejecuta si ya se está ejecutando

He creado una tarea programada de copia de seguridad de mis carpetas correctamente lo que estoy bastante orgulloso de. Sin embargo, al ver los resultados de las copias de seguridad, descubrí que mi script de respaldo había sido llamado más de una vez por Crontab, lo que resultó en múltiples copias de seguridad ejecutándose al mismo tiempo.

¿Hay alguna manera de garantizar que cierto script de shell no se ejecute si el mismo script ya se está ejecutando?

Gracias

+0

Pregunta similar: http://stackoverflow.com/questions/ 1440967/how-do-i-make-sure-my-bash-script-isnt-already-running – mizo

+0

Consulte [Gestión de procesos] (http://mywiki.wooledge.org/ProcessManagement). –

Respuesta

33

Una solución sin condiciones de carrera o problemas de salida anticipada es utilizar un archivo de bloqueo. La utilidad flock maneja muy bien y se puede utilizar como esto:

flock -n /var/run/your.lockfile -c /your/script 

Se volverá inmediatamente con un 0 estado no si el guión ya está en marcha.

0

Puede usar un archivo tmp.
Nombrado como tmpCronBkp.a, tmpCronBkp.b, tmpCronBkp.c ... etc. Reeditado de su secuencia de comandos de copia de seguridad.

Cree que en el arranque de la escritura y eliminarlo al final ...

En un tiempo, comprobar si el archivo existe o no, y qué archivo existe.

¿Has probado de esta manera?

+0

No estoy seguro de haber aclarado por completo, pero quiero asegurarme de que mi script de shell no se vuelva a ejecutar, si ya ha sido invocado por CRON y activo – Industrial

+0

Deje que este archivo contenga el PID del proceso iniciado. Entonces podrás descubrir si se está ejecutando. – akond

+0

sí, puede verificar el archivo tmp y salir de scrit si el archivo existe. – elp

7

la forma habitual y simple de hacer esto es poner algo como:

if [[ -f /tmp/myscript.running ]] ; then 
    exit 
fi 
touch /tmp/myscript.running 

en la parte superior de ustedes guión y

rm -f /tmp/myscript.running 

al final, y en trap funciones en caso de que no llega al final

Esto todavía tiene algunos problemas potenciales (como una condición de carrera en la parte superior), pero lo hará en la gran mayoría de los casos.

+0

esto evitará que la secuencia de comandos se ejecute si se ejecutó anteriormente. – unbeli

+0

@unbeli: no, no lo hará, porque elimina el archivo centinela al salir. – paxdiablo

+9

Hay una condición de carrera debido a TOCTOU (tiempo de verificación, tiempo de uso) entre 'el archivo no existe' y 'crear el archivo'. El mecanismo atómico es 'mkdir /tmp/myscript.running 2>/dev/null'. Si el directorio existe, 'mkdir' fallará, y el kernel asegurará que solo uno de los comandos' mkdir' ejecutados simultáneamente (llamadas al sistema) tenga éxito. –

5

Una buena forma y sin un archivo de bloqueo:

ps | grep $0 | grep -v grep > /var/tmp/$0.pid 
pids=$(cat /var/tmp/$0.pid | cut -d ' ' -f 1) 
for pid in $pids 
do 
    if [ $pid -ne $$ ]; then 
     logprint " $0 is already running. Exiting" 
     exit 7 
    fi 
done 
rm -f /var/tmp/$0.pid 

Esto lo hace sin un archivo de bloqueo, lo cual es genial. ps en un archivo temporal, raspe el primer campo (pid #) y búsquenos. Si encontramos uno diferente, entonces alguien ya se está ejecutando. El grep $ 0 es acortar la lista a solo aquellas instancias de este programa, y ​​grep -v grep se deshace de la línea que es grep en sí :) :)

+1

. Es más simple usar pgrep: 'pids = $ (pgrep $ 0); para pid en $ pids' – Jeremy

Cuestiones relacionadas