J'ai une tâche launchd qui exécute un bash script périodiquement, et cela fonctionne très bien. Cependant, si je modifie le script pendant que la tâche est en cours d'exécution, soit en l'éditant directement, soit en le remplaçant par une copie mise à jour, cela peut amener la tâche en cours d'exécution à cracher une charge d'erreurs de syntaxe ou pire, à avoir un comportement imprévisible.
Le problème semble être qu'au lieu de charger le script en mémoire, ou de maintenir ouvert le fichier tel qu'il était au moment de l'exécution, launchd (ou probablement bash lui-même) charge le fichier en direct ligne par ligne, ce qui signifie que toute modification du script semble être reflétée en temps réel, ce qui entraîne des erreurs.
Pour tenter d'illustrer le problème, considérons l'exemple suivant :
if [ "$foo" = '1' ]; then
do_something_that_takes_time
fi
Maintenant, imaginez que le script s'exécute à la ligne 2 ( do_something_that_takes_time
) et j'échange le script, en supprimant l'élément if/fi
bloquer entièrement. Quand le script passe à la ligne 3, il ne trouvera plus de fi
et continuera à exécuter en s'attendant à trouver une solution. fi
mais ne le fera jamais, ce qui entraînera une erreur éventuelle (fin de fichier inattendue). Il peut aussi finir par sauter des commandes (qui ont été déplacées vers le haut suite à la suppression de lignes).
Bien sûr, je peux éviter ce problème en déchargeant la tâche launchd, en la mettant à jour, puis en la rechargeant, mais ce n'est pas très pratique, surtout pour les tâches qui peuvent prendre beaucoup de temps à se terminer (je préférerais les laisser se terminer, mais il ne semble pas y avoir de moyen de le faire et d'échanger le fichier à ce moment-là). Sinon, je dois ajouter un mécanisme pour empêcher la tâche de se relancer, afin que je puisse échanger le nouveau script à mon gré, mais cela semble être une étape supplémentaire inutile alors que Bash devrait simplement exécuter le script que je lui ai dit de faire, au moment où il a commencé.
Ma question est donc la suivante : existe-t-il un moyen de forcer launchd (ou Bash) à exécuter le script uniquement tel qu'il était au début de la tâche ? Par exemple en le chargeant entièrement en mémoire avant de l'exécuter, ou en le chargeant à partir d'un file-handle ouvert qui ne changera pas ?
Je poste ceci ici parce que je ne suis pas tout à fait sûr si c'est une bizarrerie de Bash en général, ou si c'est potentiellement spécifique à Mac d'une certaine manière. Le volume sur lequel je m'exécute utilise APFS, et devrait donc être copié sur l'écriture, donc je ne m'attendrais pas à ce que ce comportement se produise (car un handle de fichier ouvert devrait continuer à pointer sur l'ancien fichier, en ignorant les modifications apportées).