Norbert Lange Norbert Lange - 29 days ago 9
Bash Question

Why doesn't set -e cause a failure with `false || false && true`?

Can't figure out a fitting title, I don't understand the behavior in dash/bash. Namely I am using set -e to bail out if a command fails, and command groups to handle the positive result.

ie. the general scheme is:

[ ! wantcommand ] || command


Than means the command only gets executed if needed, and a failure will automatically kill the script.

There might be some postprocessing necessary, in that case I use this:

[ ! wantcommand ] || { command && postprocess; }


This has led to some curious bughunting, as this wont kill the shell and I cant get behind the reason. I have to go through some chunks of shell code now, but would like to understand the reason.

for testing:

bash -c 'set -e; { false || false && echo "post" ; }; echo "ec $?"'


or:

bash -c 'set -e; { set -e; false || false && echo "post" ; }; echo "ec $?"'


Note: I am not asking for a fix, but primary why the returncode is 1, but the shell wont quit

Answer

set -e only bails on unchecked failures.

When you branch on a failure (using if, until, while, && or ||), that failure is checked.

If the specification were not written in this manner, short-circuiting boolean operations could not effectively be used for flow control because the false branches would always cause an exit.


To quote from the specification, with emphasis added:

When this option is on, if a simple command fails for any of the reasons listed in Consequences of Shell Errors or returns an exit status value >0, and is not part of the compound list following a while, until, or if keyword, and is not a part of an AND or OR list, and is not a pipeline preceded by the ! reserved word, then the shell shall immediately exit.


To inject some opinion here -- I'd strongly suggest reading BashFAQ #105 and ensuring that you fully understand all behaviors described therein before making the decision to use set -e rather than implementing explicit error-handling by hand. The FVUE wiki further describes the distinctions in behavior between set -e in bash-native mode and POSIX mode, which should likewise be understood.