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:
#!/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.
Permalink
Sorry bro, this is not a feature, this is a classic use of scripts