Sin embargo, quiero hablar sobre varios enfoques rotos y semi-viables que usan ps
y las muchas advertencias que tienen, ya que sigo viendo que la gente los usa.
Esta respuesta es realmente la respuesta a "¿Por qué no usar ps
y grep
manejar el bloqueo en el shell?"
Enfoque roto # 1
Primero, un enfoque dado en otra respuesta que tiene algunos votos positivos a pesar de que no funciona (y nunca podría funcionar) y claramente nunca se probó:
running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do
echo Already locked
exit 6
fi
Arreglemos los errores de sintaxis y los ps
argumentos rotos y obtengamos:
running_proc=$(ps -C bash -o pid,cmd | grep "$0");
echo "$running_proc"
if [[ "$running_proc" != "$$ bash $0" ]]; then
echo Already locked
exit 6
fi
Este script siempre saldrá de 6, siempre, sin importar cómo lo ejecute.
Si lo ejecuta con ./myscript
, entonces la ps
salida será 12345 -bash
, que no coincide con la cadena requerida 12345 bash ./myscript
, por lo que fallará.
Si lo ejecutas bash myscript
, las cosas se ponen más interesantes. El proceso bash se bifurca para ejecutar la canalización, y el shell secundario ejecuta el ps
y grep
. Tanto el shell original como el shell hijo aparecerán en la ps
salida, algo así:
25793 bash myscript
25795 bash myscript
Esa no es la salida esperada $$ bash $0
, por lo que su script se cerrará.
Enfoque roto # 2
Ahora, para ser justos con el usuario que escribió el enfoque roto # 1, hice algo similar cuando probé esto por primera vez:
if otherpids="$(pgrep -f "$0" | grep -vFx "$$")" ; then
echo >&2 "There are other copies of the script running; exiting."
ps >&2 -fq "${otherpids//$'\n'/ }" # -q takes about a tenth the time as -p
exit 1
fi
Esto casi funciona. Pero el hecho de bifurcarse para hacer correr la tubería arroja esto. Así que este siempre saldrá, también.
Enfoque poco confiable # 3
pids_this_script="$(pgrep -f "$0")"
if not_this_process="$(echo "$pids_this_script" | grep -vFx "$$")"; then
echo >&2 "There are other copies of this script running; exiting."
ps -fq "${not_this_process//$'\n'/ }"
exit 1
fi
Esta versión evita el problema de la bifurcación de la tubería en el enfoque n. ° 2 al obtener primero todos los PID que tienen el script actual en sus argumentos de línea de comando y luego filtrar esa lista pid, por separado, para omitir el PID del script actual.
Esto podría funcionar ... siempre que ningún otro proceso tenga una línea de comando que coincida con $0
, y siempre que el script se llame de la misma manera (por ejemplo, si se llama con una ruta relativa y luego una ruta absoluta, la última instancia no notará la primera )
Enfoque poco confiable # 4
Entonces, ¿qué pasa si omitimos la verificación de la línea de comando completa, ya que eso podría no indicar que un script se está ejecutando realmente y, en su lsof
lugar , verificamos para encontrar todos los procesos que tienen abierto este script?
Bueno, sí, este enfoque en realidad no es tan malo:
if otherpids="$(lsof -t "$0" | grep -vFx "$$")"; then
echo >&2 "Error: There are other processes that have this script open - most likely other copies of the script running. Exiting to avoid conflicts."
ps >&2 -fq "${otherpids//$'\n'/ }"
exit 1
fi
Por supuesto, si se está ejecutando una copia del script, la nueva instancia se iniciará perfectamente y tendrá dos copias ejecutándose.
O si se modifica la secuencia de comandos en ejecución (por ejemplo, con Vim o con a git checkout
), entonces la "nueva" versión de la secuencia de comandos se iniciará sin problemas, ya que tanto Vim como git checkout
un nuevo archivo (un nuevo inodo) en lugar del el viejo.
Sin embargo, si el script nunca se modifica y nunca se copia, entonces esta versión es bastante buena. No hay condición de carrera porque el archivo de secuencia de comandos ya debe estar abierto antes de que se pueda alcanzar la verificación.
Todavía puede haber falsos positivos si otro proceso tiene el archivo de script abierto, pero tenga en cuenta que incluso si está abierto para editar en Vim, vim no mantiene abierto el archivo de script, por lo que no dará lugar a falsos positivos.
Pero recuerde, no use este enfoque si el script se puede editar o copiar, ya que obtendrá falsos negativos, es decir, se ejecutarán varias instancias a la vez, por lo que el hecho de editar con Vim no da falsos positivos. para ti. Lo menciono, sin embargo, porque el enfoque # 3 no dar falsos positivos (es decir, se niega a iniciar) si tiene el guión abierto con Vim.
Entonces, ¿qué hacer, entonces?
La respuesta más votada a esta pregunta ofrece un buen enfoque sólido.
Quizás pueda escribir uno mejor ... pero si no comprende todos los problemas y advertencias con todos los enfoques anteriores, es probable que no escriba un método de bloqueo que los evite a todos.
kill
; y parece ser una buena práctica almacenar el propio pid en el archivo de bloqueo, en lugar de solo tocarlo.