Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../bash -I../bash/include -I../bash/lib -g -O2 uname output: Linux hotel562.server4you.de 2.6.15-27-amd64-xeon #1 SMP PREEMPT Sat Sep 16 02:12:56 UTC 2006 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu
Bash Version: 3.1 Patch Level: 17 Release Status: release Description: Today I recognized a strange behavior of Bash with set -e and operator || (same for && as well). $ bash -ec 'set -e; ( set -e; /bin/false; echo wrong; ) || echo correct' wrong I would expect the output to be "correct", but it is "wrong". The bash comes from Ubuntu 6.06 LTS, however Debian Etch shows the same. Also ksh and zsh reproduce this strange behavior as well, so perhaps it's an undocumented feature? Same is true for "if" constructs: $ bash -ec 'set -e; if ! ( set -e; /bin/false; echo wrong; ); then echo correct; fi' wrong In contrast look at following line: $ bash -ec 'set -e; ( set -e; /bin/false; echo wrong; ); [ 0 = $? ] || echo correct' correct This outputs what I do expect from all above commands to output. Apparently the "||" operator (and "&&" and "if" as well) disable "set -e" within subshell execution. You even cannot re-enable it again! Is it only me who thinks that is very strange? At least this sideeffect *must* be documented somewhere very clearly (manual and help), as it may be crucial to have your commands terminated as soon as they do not return true. However surrounding commands with a sub-shell (which is convenient to PWD-changes or "catch exit" like in the "set -e" case) and then adding some '|| sequence' (or "if") does strange things. Note that this "set -e globally disabled" feature propagates through the complete script within your current shell. If you use any conditional on the command, even with function invocations, you will see this behavior. This means, when it comes to "set -e", there is a fundamental difference if you define some fn within the shell, and invoke "fn;" or "if fn; then ...", as in the first case it is run under "set -e" control, in the latter it isn't. Repeat-By: Following two commands behave strangely IMHO: bash -ec 'set -e; ( set -e; /bin/false; echo wrong; ) || echo correct' bash -ec 'set -e; if ! ( set -e; /bin/false; echo wrong; ); then echo correct; fi' Fix: Abstain from using script function with "if" or other conditionals. Instead check the return code manually, which is very tedious, like in: bash -ec 'set -e; ( set -e; /bin/false; echo wrong; ); [ 0 = $? ] || echo correct' Another "solution" seems to downgrade to Bash2 (taken from an old SuSE-Linux): $ bash --version GNU bash, version 2.05.0(1)-release (i386-suse-linux) Copyright 2000 Free Software Foundation, Inc. $ bash -ec 'set -e; ( set -e; /bin/false; echo wrong; ) || echo correct' correct However note on a very old KSH I can see the considered wrong behavior, too: $ ksh -c 'echo $KSH_VERSION; set -e; ( set -e; /bin/false; echo wrong; ) || echo correct' @(#)PD KSH v5.2.14 99/07/13.2 wrong