I have a launchd task that runs a bash script periodically, and this works great. However, if I change the script while the task is running, either by editing it directly, or swapping it with an updated copy, it can cause the running task to spew out a load of syntax errors or worse, have unpredictable behaviour.
The problem appears to be that instead of loading the script into memory, or holding open the file as it was at the time of execution, launchd (or probably bash itself) is loading the live file line-by-line, this means that any changes to the script appear to be reflected in real time, leading to errors.
To try to illustrate the problem, consider the following:
if [ "$foo" = '1' ]; then do_something_that_takes_time fi
Now, imagine the script is running at line 2 (
do_something_that_takes_time) and I swap out the script, removing the
if/fi block entirely. When the script moves onto line 3, it will no longer find
fi, and will continue executing expecting to find a
fi but never will, resulting in an eventual error (unexpected end of file). It may also end up skipping commands (that were moved up as a result of removing lines).
Of course I can avoid this issue by unloading the launchd task, updating, then reloading it, but this isn't very convenient, especially for tasks that can take a long time to complete (as I'd prefer to let them finish, but there seems no way to do so and swap in the file at that point). Otherwise I have to add in some mechanism for prevent the task from re-launching, so I can swap in the new script at my leisure, but this seems like an unnecessary extra step when Bash should just be running the script I told it to, at the time it started.
So my question is this; is there some way that I can force launchd (or Bash) to execute the script only as it was when the task began? For example by fully loading it into memory before executing, or loading from an open file-handle that won't change?
I'm posting this here because I'm not entirely sure if this is a quirk of Bash in general, or potentially Mac specific in some way. The volume I'm executing from is using APFS, so should be copy-on-write, so I wouldn't expect this behaviour to occur (as an open file handle should continue to point to the old file, ignoring any changes that are made).