Tengo una tarea launchd que ejecuta un bash script periódicamente, y esto funciona muy bien. Sin embargo, si cambio el script mientras la tarea se está ejecutando, ya sea editándolo directamente, o cambiándolo por una copia actualizada, puede hacer que la tarea en ejecución arroje un montón de errores de sintaxis o, peor aún, tenga un comportamiento impredecible.
El problema parece ser que en lugar de cargar el script en memoria, o mantener abierto el archivo tal y como estaba en el momento de la ejecución, launchd (o probablemente el propio bash) está cargando el archivo en vivo línea a línea, esto significa que cualquier cambio en el script parece reflejarse en tiempo real, provocando errores.
Para tratar de ilustrar el problema, considere lo siguiente:
if [ "$foo" = '1' ]; then
do_something_that_takes_time
fi
Ahora, imagina que el script se ejecuta en la línea 2 ( do_something_that_takes_time
) y cambio el script, eliminando el if/fi
bloque por completo. Cuando el script pasa a la línea 3, ya no encontrará fi
y seguirá ejecutando esperando encontrar un fi
pero nunca lo hará, resultando en un eventual error (final inesperado del archivo). También puede acabar saltándose comandos (que se adelantaron como resultado de la eliminación de líneas).
Por supuesto que puedo evitar este problema descargando la tarea launchd, actualizándola, y luego volviéndola a cargar, pero esto no es muy conveniente, especialmente para las tareas que pueden tardar mucho tiempo en completarse (ya que preferiría dejarlas terminar, pero no parece haber manera de hacerlo y cambiar el archivo en ese momento). De lo contrario, tengo que añadir algún mecanismo para evitar que la tarea se relance, de modo que pueda intercambiar el nuevo script a mi antojo, pero esto parece un paso extra innecesario cuando Bash debería simplemente ejecutar el script que le indiqué, en el momento en que se inició.
Así que mi pregunta es la siguiente: ¿hay alguna forma de forzar a launchd (o a Bash) a ejecutar el script sólo como estaba cuando comenzó la tarea? Por ejemplo, cargándolo completamente en la memoria antes de ejecutarlo, o cargándolo desde un archivo abierto que no cambie.
Estoy publicando esto aquí porque no estoy del todo seguro de si esto es una rareza de Bash en general, o potencialmente Mac específico de alguna manera. El volumen que estoy ejecutando desde está usando APFS, por lo que debería ser copia-en-escritura, por lo que no esperaría que este comportamiento ocurriera (ya que un manejador de archivo abierto debería continuar apuntando al archivo antiguo, ignorando cualquier cambio que se haga).