3

Why is the third case returning success with exit code 0?

case 1 ~$ bash -c 'set -e; false || true; echo success'; echo $?
success
0
case 2 ~$ bash -c 'set -e; true || false; echo success'; echo $?
success
0
case 3 ~$ bash -c 'set -e; false && true; echo success'; echo $?
success
0
case 4 ~$ bash -c 'set -e; true && false; echo success'; echo $?
1
case 5 ~$ bash -c 'set -e; false || false; echo success'; echo $?
1
case 6 ~$  bash -c 'set -e; false && false; echo success'; echo $?
success
0
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
png
  • 5,990
  • 2
  • 25
  • 16
  • 4
    See [BashFAQ #105](http://mywiki.wooledge.org/BashFAQ/105): `set -e` is subtle and hard to reason about (and has even-more-subtle implementation differences between different shells and release versions), and a large proportion of the bash community is in agreement with the proposition that it should never be used. – Charles Duffy Jan 02 '17 at 21:26
  • 2
    Quoting the page " It has useful semantics, so to exclude it from the toolbox is to give into FUD." – eckes Jan 02 '17 at 21:37
  • @eckes: that's only a certain obscure user's opinion. GreyCat and geirha have another opinion. – gniourf_gniourf Jan 02 '17 at 21:41
  • @eckes, ...notably, GreyCat is the primary *author* of that FAQ, and the BashGuide, and primary person responsible for the Freenode #bash IRC channel. If there's going to be argument from authority, it's worth noting who the relevant authorities are. – Charles Duffy Jan 02 '17 at 22:10
  • Feel free to argument by authority - I think it is typically a bad idea to have shell scripts without `set -e`. It does enforce proper error handling. That alone is worth it. – eckes Jan 03 '17 at 16:33

3 Answers3

4

The bash documentation for set -e says:

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 ||, [...]

The command list in question is false && true. The failing command is false, which is not the last command in the list, so the shell does not exit. The 0 you're seeing is the exit status of echo success.

melpomene
  • 84,125
  • 8
  • 85
  • 148
2

set -e is a bit subtle.

From the reference:

-e

When this option is on, when any command fails (for any of the reasons listed in Consequences of Shell Errors or by returning an exit status greater than zero), the shell immediately shall exit, as if by executing the exit special built-in utility with no arguments, with the following exceptions:

  1. The failure of any individual command in a multi-command pipeline shall not cause the shell to exit. Only the failure of the pipeline itself shall be considered.
  2. 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.

  3. If the exit status of a compound command other than a subshell command was the result of a failure while -e was being ignored, then -e shall not apply to this command.

This requirement applies to the shell environment and each subshell environment separately. For example, in:

set -e; (false; echo one) | cat; echo two

the false command causes the subshell to exit without executing echo one; however, echo two is executed because the exit status of the pipeline (false; echo one) | cat is zero.

Since false && true is part of an AND or OR list and false isn't the last, the shell doesn't exit immediately.

So echo success is executed, and it's return code is 0.

By the way, have you noticed case 6?

gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
  • 1
    By that logic, case 4 should write "success" as well, since `true && false` is an AND list. The exception mentioned in melpomene's answer is very relevant here. – Heinzi Jan 02 '17 at 21:23
  • @Heinzi: yeah, I should have linked the [latest version](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set), they augmented this part, actually... oh well. – gniourf_gniourf Jan 02 '17 at 21:36
0

true && false; echo success returns the return code from echo which is 0.

 bash -c 'false && true'; echo $?

yields 1 as expected. Pheew!

Aside: bash -c 'set -e; false || false; echo success'; echo $? yields return code 1 because second command does not execute echo (stops at false because errors stop the current command), note that success is not printed.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219