What's the best way to include error cleanup logic for shell scripts?
Specifically, I have a script that does something like this:
mount a x mount b y setup_thing mount c z do_something umount z cleanup_thing umount y umount x
Any of the mounts, plus
do_something itself, might fail. If, say, the
mount c z fails, I would like the script to unmount the mounts that did succeed before exiting.
I don't want to have to repeat the cleanup code multiple times, and I don't want to wrap everything into an if-nest (because then you have to re-indent everything if you add an extra mount).
Is there a way to create a finally-stack or something, so the above could be written as:
set -e mount a x && finally umount x mount b y && finally umount y setup_thing && finally cleanup_thing mount c z && finally umount z do_something
The idea being that once the "finally" command is registered it will execute (in reverse order) that command on exit, pass or fail -- but the things that didn't get set up successfully don't get cleaned up (because the cleanup might not be safe to execute if the setup failed).
Or to put it another way, if everything succeeds then it will execute
umount x in that order -- same if only
do_something fails. But if the
mount b y fails then it will only execute
(And regardless it needs to exit with 0 or not-0 appropriately, although I don't need to preserve the exact exit code on failure.)
I know there's a
trap builtin that lets you run a command on exit, but it only supports one command and replaces it each time. Is there a way to extend this into a stack like above? Or some other clean way to do it?
In error-handling patterns from Ye Olde C code you'd probably achieve something like this with
x || goto cleanup_before_x but of course there's no goto.
Ideally something that works in (da)sh, although I'm ok with requiring bash if that simplifies things. (Perhaps using arrays?)