Bash Shell Script – How to Exit on Backtick Failure Similar to Pipefail

bashshell-script

So I like to harden my bash scripts wherever I can (and when not able to delegate to a language like Python/Ruby) to ensure errors do not go uncaught.

In that vein I have a strict.sh, which contains things like:

set -e
set -u
set -o pipefail

And source it in other scripts.
However, while pipefail would pick up:

false | echo it kept going | true

It will not pick up:

echo The output is '`false; echo something else`' 

The output would be

The output is ''

False returns non-zero status, and no-stdout. In a pipe it would have failed, but here the error isn't caught. When this is actually a calculation stored in a variable for later, and the value is set to blank, this may then cause later problems.

So – is there a way to get bash to treat a non-zero returncode inside a backtick as reason enough to exit?

Best Answer

Solution

If you are running Bash 4.4 or later, you can use the shopt option inherit_errexit to do just that. You can check compatibility from within Bash using echo $BASH_VERSION.

Here is the shebang you would use if Bash 4.4 or later were installed and came before /bin in your $PATH:

#!/usr/bin/env -S bash -euET -o pipefail -O inherit_errexit

The -S is there to coax Linux’s env into accepting more than one argument for bash, as kindly pointed out by @UVV and explained further on StackOverflow.


Background

inherit_errexit is an option to shopt, while the rest of the arguments are options to set. In most modern iterations, they can be passed directly to bash when invoking the shell.

Let’s review the options you have already been using:

  • -u/-o nounset, as the name ambiguously hints, disallows dereferencing of variables that have not been set; e.g., $IJUSTMADETHISUP.
  • -e/-o errexit does some of what you are requesting: it causes directly called shell commands with nonzero return values to cause the shell to exit entirely.
  • -o pipefail is needed to extend this to commands whose output is redirected with an I/O pipe |.

Now for the options I’ve added:

  • -O inherit_errexit further extends this functionality (exiting on nonzero status code) to commands called from within subshells $(...).
  • The -E/-o errtrace and -T/-o functrace options are there for the comparatively rare case that you use trap to perform an action when the shell receives a signal. These two options extend signal handlers to the inner bodies of shell functions for ERR signals and DEBUG/RETURN signals, respectively.

See also

Related Question