20

I use set -e to stop bash script on first error.

All work OK unless I use command with &&:

$ cat script
set -e
cd not_existing_dir && echo 123
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
I'm running! =P
$

compared with:

$ cat script
set -e
cd not_existing_dir
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
$

The first example still echoes I'm running!, but the second one doesn't. Why do they behave differently?

UPD. Similar question: https://stackoverflow.com/questions/6930295/set-e-and-short-tests

3 Answers3

14

This is documented behavior.  The bash(1) man page says, for set -e,

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 following the if or elif reserved words, 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 value is being inverted with !.
[Emphasis added.]

And the POSIX Shell Command Language Specification confirms that this is the correct behavior:

The -e setting shall be ignored when executing the compound list following the while, until,if, or elif reserved word, a pipeline beginning with the ! reserved word, or any command of an AND-OR list other than the last.

and Section 2.9.3 Lists of that document defines

An AND-OR list is a sequence of one or more pipelines separated by the operators "&&" and "||" .

12

The set -e option doesn't have effect in some situations, and this is the standard behavior and portable across POSIX compliant shell.


The failed command is part of pipeline:

false | true; echo printed

will print printed.

And only the failure of the pipeline itself is considered:

true | false; echo 'not printed'

will print nothing.


The failed command run in the compound list following the while, until, if, elif reserved word, a pipeline beginning with the ! reserved word, or any command as part of && or || list except the last one:

false || true; echo printed

The last command fails still make set -e affected:

true && false; echo 'not printed'

The subshell fails in a compound command:

(false; echo 'not printed') | cat -; echo printed
cuonglm
  • 153,898
  • Thank you! It would be clearer to use echo "printed" and echo "not_printed" in your examples (instead of echo 1). – Aleksei Chernenkov Sep 27 '16 at 09:35
  • 3
    Note that set -e causes an exit in (false && true); echo not here, but not in { false && true; }; echo here, though YMMV with different shells and even different versions of a same shell. I wouldn't touch set -e with a barge pole and would do proper error handling instead. – Stéphane Chazelas Sep 27 '16 at 13:47
2

my guess is if-then condition as a whole evaluate to true.

I tried

set -e
if cd not_existing_dir
then  echo 123
fi
echo "I'm running! =P"

who give

-bash: cd: not_existing_dir: No such file or directory
I'm running! =P

error code is catch by if condition, thus bash will not trigger end of execution.

Archemar
  • 31,554