El 19 de agosto de 2013, Randal L. Schwartz publicó este script de shell, que tenía la intención de garantizar, en Linux, "que solo se ejecute una instancia de [el] script, sin condiciones de carrera o tener que limpiar los archivos de bloqueo":
#!/bin/sh
# randal_l_schwartz_001.sh
(
if ! flock -n -x 0
then
echo "$$ cannot get flock"
exit 0
fi
echo "$$ start"
sleep 10 # for testing. put the real task here
echo "$$ end"
) < $0
Parece funcionar como se anuncia:
$ ./randal_l_schwartz_001.sh & ./randal_l_schwartz_001.sh
[1] 11863
11863 start
11864 cannot get flock
$ 11863 end
[1]+ Done ./randal_l_schwartz_001.sh
$
Esto es lo que entiendo:
- El script redirige (
<
) una copia de sus propios contenidos (es decir, de$0
) al STDIN (es decir, el descriptor de archivo0
) de una subshell. - Dentro de la subshell, el script intenta obtener un lock (
flock -n -x
) exclusivo y no bloqueador en el descriptor de archivo0
.- Si ese intento falla, la subshell sale (y también lo hace el script principal, ya que no hay nada más que pueda hacer).
- Si el intento tiene éxito, la subshell ejecuta la tarea deseada.
Aquí están mis preguntas:
- ¿Por qué el script necesita redirigir, a un descriptor de archivo heredado por la subshell, una copia de su propio contenido en lugar de, digamos, el contenido de algún otro archivo? (Intenté redirigir desde un archivo diferente y volver a ejecutar como se indicó anteriormente, y el orden de ejecución cambió: la tarea no en segundo plano ganó el bloqueo antes que la de fondo. Entonces, tal vez usar el contenido del archivo evite las condiciones de carrera; pero ¿cómo?)
- ¿Por qué el script necesita redirigir, a un descriptor de archivo heredado por la subshell, una copia del contenido de un archivo, de todos modos?
- ¿Por qué mantener un bloqueo exclusivo en el descriptor de archivo
0
en un shell impide que una copia del mismo script, que se ejecuta en un shell diferente, obtenga un bloqueo exclusivo en el descriptor de archivo0
? No conchas tienen sus propias copias independientes de los descriptores de archivos estándar (0
,1
y2
, es decir, stdin, stdout y stderr)?