set -e
means that the reader of the script cannot know what the script will do when looking at code snippets out of context. (This is a bit tongue-in-cheek, but gets to the heart of the matter.) I have been opposed to the use of errexit
for many years and have recently been doing a fair bit of work in an environment where shell snippets are accumulated as templates. errexit
is enabled by default in this environment, but that is largely irrelevant as any previous snippet may disable errexit and the order in which the templates are gathered is not well known and probably non-deterministic. But consider the simple case in which you look at a few lines without context in a shell script:
$ sed -n 3,6p sample-script echo this will be printedset -e # enable errexit again just to be sure it's onfalseecho but errexit is enabled so this will not be printed
Since errexit is enabled, the reader is being very reasonable in expecting that the line "but errexit is enabled so this will not be printed" will not in fact be written. But, consider the actual execution of the script:
$ ./sample-script this will be printedbut errexit is enabled so this will not be printed
There is no magical juju happening, or anything terribly bizarre that is causing this behavior. This is simply the normal behavior of the shell. On the other hand, if we change the script slightly and make the desired behavior explicit, the unexpected behavior goes away. Consider:
$ cat sample-script-2 #!/bin/bash -eifecho this will be printedfalse || exitecho but this is not printed because the author was explicit about exitingthen : ; fi$ ./sample-script-2 this will be printed
errexit was an attempt to make life easier for script writers and maintainers, but it failed. And it continues to fail. To borrow from python: "Explicit is better than implicit". If you want your script to terminate if a command returns non-zero, write cmd || exit
. If you want your script to maybe sometimes fail when a command returns non-zero and you want to ensure that the maintainers of the script really won't know what actually happens, write set -e; cmd