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
0en 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,1y2, es decir, stdin, stdout y stderr)?