Stopping bash script on error, and what can possibly go wrong

TL;DR Don’t mix set -e and && operators in bash, it’s not going to work well.

What is ‘set -e’

Bash command set -e stops the script when any of the script commands fails. Or something like that, the big hairy devil is in the details. Suppose we want to download, build, test, and deploy some code using a bash script. We want to stop the entire script immediately if any of the steps fails. This is not something bash would do by default. We can combine all the steps using the && operator, but in real life it becomes really annoying really quickly, especially for large scripts with long winded commands:

download &&
do_build &&
do_test &&

Alternatively, we can put set -e in the beginning of the script, and leave the rest as is:

set -e

‘set -e’ does not mix well with &&

set -e comes with quite a few strings attached: in particular, it will stop only for “simple” commands. See this Stack Overflow question for more details.

Suppose ‘do_build’ fails in the following script:

set -e
do_build && do_test

Will the script stop? No! It will skip the ‘do_test’ command and go strait ahead to ‘deploy’. If ‘deploy’ manages to succeed, the whole script succeeds, even though we just failed the build and skipped the test. How do I know? The hard way. Our CI build failed in a similar manner, but overall result was “green”.

This is not a bug, this is a feature. do_build && do_test is not a simple command, so set -e treats it differently.

false && false and false && true will NOT stop the script.

On the other hand, false on its own, as well as false || false and true && false WILL stop the script.

Of course, if you read the documentation carefully, it all has an explanation, but the bottom line is very simple: do not mix driving and alcohol set -e and operator &&. Choose either one or the other, but not both.

1 Comment

  1. Sorry bro, this is not a feature, this is a classic use of scripts


Leave a Reply

Your email address will not be published. Required fields are marked *