[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Operator || disables set -e in subshells: Bug or feature?

From: bug-bash-reply
Subject: Operator || disables set -e in subshells: Bug or feature?
Date: Mon, 19 May 2008 15:16:28 +0200

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


        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'

        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'

        In contrast look at following line:

        $ bash -ec 'set -e; ( set -e; /bin/false; echo wrong; ); [ 0 = $? ] || 
echo 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 
        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 
        "fn;" or "if fn; then ...", as in the first case it is run under "set 
-e" control,
        in the latter it isn't.


        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'

        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 

        $ 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'
        However note on a very old KSH I can see the considered wrong behavior, 

        $ ksh -c 'echo $KSH_VERSION; set -e; ( set -e; /bin/false; echo wrong; 
) || echo correct'
        @(#)PD KSH v5.2.14 99/07/13.2

reply via email to

[Prev in Thread] Current Thread [Next in Thread]