TL;DR Don’t mix
set -e and
&& operators in bash, it’s not going to work well.
What is ‘set -e’
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:
#!/bin/bash download && do_build && do_test && deploy
Alternatively, we can put
set -e in the beginning of the script, and leave the rest as is:
#!/bin/bash set -e download do_build do_test deploy
‘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:
#!/bin/bash set -e download do_build && do_test deploy
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.