[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
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
- Operator || disables set -e in subshells: Bug or feature?,
bug-bash-reply <=