help-bash
[Top][All Lists]
Advanced

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

Re: [Help-bash] Source builtin and error handling


From: Eric Blake
Subject: Re: [Help-bash] Source builtin and error handling
Date: Mon, 30 Nov 2015 15:54:17 -0700
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0

On 11/30/2015 01:58 PM, Marcin Świgoń wrote:
> Dear bash experts,
> 
> Today I came across a strange situation when using set -e, source
> builtin and error handling.

'set -e' is probably not what you want to use. It almost never is.  It
is specified to have backwards-compatible semantics, but those semantics
are non-intuitive.

> 
> Please consider following scripts:
> 
> #====================
> # source run_this
> #====================
> source src1 || exit 1

The fact that you are calling 'source src1' on the left side of || means
that 'set -e' has NO effect for the entire duration of 'src1'.  That's
how 'set -e' is required to behave.  It is probably not what you wanted,
but it is what is required to happen.

> echo "run_this: should I get here after src1?"

Therefore, yes, you should get here after src1, if src1 had a zero exit
status.

> source src2 || exit 1
> echo "run_this: should I get here after src2?"
> 
> #====================
> # source src1
> #====================
> set -e
> false
> echo "src1: should I get here?"

And indeed, src1 has a 0 exit status, because the echo was successful.
Why didn't src1 short-circuit and exit early after false?  Because 'set
-e' had no effect (the entire src1 script was run on the left side of ||
in the caller).  So the behavior after src1 is correct.

> 
> #====================
> # source src2
> #====================
> set -e
> source src3 || echo "src3 does not exist"
> false
> echo "src2: should I get here?"

However, the fact that you do not get here seems to be a bug in bash's
'set -e' handling.  I can confirm that src2 did a short-circuit exit due
to executing 'false' during src2, which in turn caused a non-zero return
status from src2 and an early exit of run_this.

I tested with Fedora 22's bash-4.3.42-1.fc22.x86_64 (4.3.42(1)-release).

Contrast it to working shells (where I patched run_this to use '.
./src1' rather than 'source src1' to favor the POSIX spelling of things,
and because bash in POSIX mode doesn't automatically look in the current
directory for source files):

$ cat run_this
. ./src1 || exit 1
echo "run_this: should I get here after src1?"
. ./src2 || exit 1
echo "run_this: should I get here after src2?"
$ bash ./run_this
src1: should I get here?
run_this: should I get here after src1?
./src2: line 3: ./src3: No such file or directory
src3 does not exist
$ bash -o posix ./run_this
src1: should I get here?
run_this: should I get here after src1?
./src2: line 3: ./src3: No such file or directory
$

Interesting - bash in POSIX mode treats a non-existent source file as
fatal, and refuses to even print the 'src3 does not exist' because it
has exited immediately (and POSIX allows that behavior).  Let's see what
other shells do:

$ ksh ./run_this
src1: should I get here?
run_this: should I get here after src1?
./run_this[4]: .[3]: .: ./src3: cannot open [No such file or directory]
$

which matches 'bash -o posix' in treating a failed '.' as an instant
exit of a non-interactive script.

But if I spell it 'source ./src3' instead of '. ./src3' inside src2,

$ ksh ./run_this
src1: should I get here?
run_this: should I get here after src1?
./run_this[4]: .[3]: .: ./src3: cannot open [No such file or directory]
src3 does not exist
src2: should I get here?
run_this: should I get here after src2?
$

So in ksh, 'source' and '.' are not quite synonyms, and the behavior of
'source' lets things continue, where src2 behaves like src1 in that 'set
-e' has no effect because things were executed on the left of ||.

How about other shells?

$ zsh ./run_this
src1: should I get here?
run_this: should I get here after src1?
./src2:.:3: no such file or directory: ./src3
src3 does not exist
src2: should I get here?
run_this: should I get here after src2?
$

so zsh behaves like ksh for 'source' (and not like ksh for '.').

$ dash ./run_this
$

Whoops - dash violates POSIX, because it short-circuited src1 execution
at the first false.

Congratulations - you've found both a bash bug and a dash bug in one
email :)

> Is this anyhow documented?
> Is this behaviour desired (sub-source with error handling magically
> activate set -e)?

The behavior of 'set -e' is documented, and the fact that it is
(usually) not what you naively want it to be is a frequent topic of
conversation on this list.  However, the magic you discovered where
'src2' doesn't follow POSIX appears to be a genuine bug.

> 
> GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)

Yikes - you really need to upgrade your bash.  Your version is
(probably) still vulnerable to shellshock.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

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