Re:How to write idempotent Bash scripts (2019)
by xorcist on Thursday December 09, 2021 @07:37AM
(#29496667)
That's not it.
Between
[ -f file.txt ] && rm file.txt
and rm -f file.txt
the latter form is preferrable because it is easier and not as prone to concurrency problems.Although it should be said that concurrency and idempotency is seldom acquired just by using force-flags in isolated spots, the whole operation needs to take it into account. There are probably more steps involved than just removing one file. The linked article leaves out the bigger picture so it's probably not very helpful. Often it is sufficient to construct the new state under a temporary name and then move it in place in one operation.
Re:How to write idempotent Bash scripts (2019)
by bashonly on Thursday December 09, 2021 @07:29AM
(#29496601)
agreed w/ your general points, but passing arguments to bash functions does not work like this:
errorHandler("ignore")
it should just be: errorHandler "ignore"
Re:How to write idempotent Bash scripts (2019)
by julian_sark on Thursday December 09, 2021 @07:37AM
(#29496664)
You are certainly correct, thanks. I hastily typed this out, my bad.
Re:How to write idempotent Bash scripts (2019)
by reacweb on Thursday December 09, 2021 @07:42AM
(#29496715)
you will probably love perl. Perl encourages this programming style :
unlink ('file.txt') or die "Can't remove file.txt: $!";
Re:How to write idempotent Bash scripts (2019)
by julian_sark on Thursday December 09, 2021 @08:27AM
(#29497058)
Somewhat paradoxically, my opinion on perl can't be (cleanly) reproduced here ;)
Never use potentially dangerous commands (rm -f) to avoid the prospect of an error!
Instead, one should practice good error handling. For some scripts and depending on the audience "set -e" may be sufficient. But usually always better:
rm file.txt || echo "Warning: Deleting file.txt failed, continuing anyway."
Or, for longer shell scripts, I always include a little function that deals with error handling. You can call it in the same way:
rm file.txt || errorHandler("ignore")
As shown above, the function can be built to take various parameters, and can then for instance abort or ignore the error. It can also take care of updating a log file.
Somewhat related, I do logging in shell scripts with a function, too:
rm file.txt && log("info", "file successfully deleted")
That way, I only need to write the code that writes log lines with nice formating and timestamps and such once.
Somewhat related, one can trap various signals in a shell script, and call a bash function when they happen. Thus, one can trap SIGEXIT and call a cleanup function that triggers on Ctrl-C, and I'm almost certain (sorry, can't test right now) one can also trap SIGERR and catch errors in a shell script nicely (though I'm not sure if that also goes for external commands inside said shell script).