According to this accepted answer using the set -e
builtin should suffice for a bash script to exit on the first error. Yet, the following script:
Because that answer is not sufficiently specific enough.
It should say (bolded text is my addition):
# Any subsequent simple commands which fail will cause the shell script to exit immediately
Since the man page reads thusly:
-e Exit immediately if a simple command (see SHELL GRAMMAR
above) exits with a non-zero status. The shell does not
exit if the command that fails is part of the command
list immediately following a while or until keyword,
part of the test in an if statement, part of a && or ││
list, or if the command’s return value is being inverted
via !. A trap on ERR, if set, is executed before the
shell exits.
And SHELL GRAMMAR
expands thusly:
SHELL GRAMMAR
Simple Commands
A simple command is a sequence of optional variable assignments fol-
lowed by blank-separated words and redirections, and terminated by a
control operator. The first word specifies the command to be executed,
and is passed as argument zero. The remaining words are passed as
arguments to the invoked command.
The return value of a simple command is its exit status, or 128+n if
the command is terminated by signal n.
I came across set -e
for Bash scripts but had problems understanding what happens regarding the evaluation of the command following the last &&
or ||
in a &&
or ||
list. I know of the following quote from http://man7.org/linux/man-pages/man1/bash.1.html about set -e
:
The shell does not exit if the command that fails is (...) part of any command executed in a
&&
or||
list except the command following the final&&
or||
(...)
To test this, I wrote a small Bash script:
#!/bin/bash
bash -c "set -e ; true ; echo -n A"
bash -c "set -e ; false ; echo -n B"
bash -c "set -e ; true && true ; echo -n C"
bash -c "set -e ; true && false ; echo -n D"
bash -c "set -e ; false && true ; echo -n E"
bash -c "set -e ; false && false ; echo -n F"
bash -c "set -e ; true || true ; echo -n G"
bash -c "set -e ; true || false ; echo -n H"
bash -c "set -e ; false || true ; echo -n I"
bash -c "set -e ; false || false ; echo -n J"
echo ""
It prints:
ACEFGHI
About A:
true
does not have a non-zero status. Therefore, the shell doesn't exit.
About B:
false
does have a non-zero status and is not part of a &&
or ||
list. Therefore, the shell exits.
About C:
This is a &&
or ||
list. We will have to look at the command following the last &&
or ||
. The command is true
which does not have a non-zero status. So it doesn't matter if the command is evaluated or not - the shell doesn't exit either way.
About D:
This is a &&
or ||
list. We will have to look at the command following the last &&
or ||
. This time, the command is false
which does have a non-zero status. So we have to check if that false
is being evaluated - which is indeed the case since &&
is following the true
. Therefore, the shell exits.
About E:
Same reasoning as with C: true
is the command following the last &&
or ||
. Therefore, the shell doesn't exit.
About F:
Similar to D: This is a &&
or ||
list. We will have to look at the command following the last &&
or ||
. Again the command is false
which does have a non-zero status. But this time it doesn't matter, because the first command is false
as well. Since it's a &&
list, the second false
won't be evaluated. Therefore, the shell doesn't exit.
About G:
Same reasoning as with C or E: true
is the command following the last &&
or ||
. Therefore, the shell doesn't exit.
About H:
This is a &&
or ||
list. We will have to look at the command following the last &&
or ||
. This command is false
which does have a non-zero status, but it won't be evaluated since ||
is preceded by true
. Therefore, the shell doesn't exit.
About I:
Same reasoning as with C, E or G: true
is the command following the last &&
or ||
. Therefore, the shell doesn't exit.
About J:
This is a &&
or ||
list. We will have to look at the command following the last &&
or ||
. This command is false
which does have a non-zero status. Since ||
is preceded by false
the second false
will be evaluated. Therefore, the shell does exit.
You should be able to apply these test cases to your case: true && false && true
. Since the command following the last &&
or ||
is true
which doesn't have a non-zero status, it doesn't matter what precedes &&
or ||
, the shell won't exit either way.
To simplify EtanReisner's detailed answer, set -e
only exits on an 'uncaught' error. In your case:
echo "about to fail" && /bin/false && echo "foo"
The failing code, /bin/false
, is followed by &&
which tests its exit code. Since &&
tests the exit code, the assumption is that the programmer knew what he was doing and anticipated that this command might fail. Ergo, the script does not exit.
By contrast, consider:
echo "about to fail" && /bin/false
The program does not test or branch on the exit code of /bin/false
. So, when /bin/false
fails, set -e
will cause the script to exit.
/bin/false
failsConsider:
set -e
echo "about to fail" && /bin/false ; echo "foo"
This version will exit if /bin/false
fails. As in the case where &&
was used, the final statement echo "foo"
would therefore only be executed if /bin/false
were to succeed.