Bash -e Doesn’t Exit As I expect

In bash scripting, it’s a good practice to exit for any unexpected/unhandled errors. Usually I enforce this by ‘bash -e my_script.sh’. Today just got a surprise with ‘bash -e’.

Check out below simple test. You might get bitten by this as well.

Permanent Link: http://dennyzhang.com/bash_errcode_exit

Here is my previous assumption. Suppose we run a shell code block with ‘bash -e’ or ‘set -e’. If any commands have problems in the middle, the whole code block shall fail and quit.

Usual Case Of ‘bash -e’

As we expect in below test, “ls /wontexists” fails. Thus we don’t see the further output generated by the second echo command.

cat > /tmp/test1.sh << EOF
#!/bin/bash
echo "msg1" && ls /wontexists
echo "should not see this"
EOF
bash -xe /tmp/test1.sh
echo $?

Problematic Example: ‘bash -e’ doesn’t exit

Running below code, we will see output of “should not see this”. And $? is ZERO! Strange, isn’t it?

cat > /tmp/test2.sh << EOF
#!/bin/bash
echo "msg1" && ls /wontexists && echo "msg2"
echo "should not see this"
EOF
bash -xe /tmp/test2.sh
echo $?

Uncover The Mystery

set -e only exits on an ‘uncaught’ error. 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 any command executed in a && or || list. To be simple, the shell does not exit if the command that fails is part of the command list.

Official explanation for bash -e1. A similar discussion in Stackoverflow2.

-e
Exit immediately if a pipeline (see
Pipelines), which may consist of a single
simple command (see Simple Commands), a list
(see Lists), or a compound command (see
Compound Commands) returns 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 any command executed in a && or ||
list except the command following the final
&& or ||, any command in a pipeline but the
last, or if the command’s return status is
being inverted with !. If a compound command
other than a subshell returns a non-zero
status because a command failed while -e was
being ignored, the shell does not exit. A
trap on ERR, if set, is executed before the
shell exits.

More Reading: Shell Redirect Output To File, And Still Have It On Screen.

Footnotes:

1 www.gnu.org/software/bash/manual/bashref.html#The-Set-Builtin

2 stackoverflow.com/questions/25794905/why-does-set-e-true-false-true-not-exit


Like our blog posts? Discuss with us on LinkedIn, Twitter Or NewsLetter.