Reputation: 10459
Following recipe to time
false
under set -e
succeeds (success in the sense that the time
output can be seen):
(
set +e
time { ( set -e; false; echo no0; ); }
echo yes0 $?
)
But following recipes fail:
(
set -e
time false
echo no1
)
As well:
(
set -e
time { false; echo no2; }
echo no2
)
As well (surprisingly it outputs yes3 under bash3 and nothing under bash4):
(
set -e
time ( false; echo no3; )
echo yes3 $?
)
As well (not very suprising):
(
set +e
time { set -e; false; echo no4; }
echo no4
)
As well (surprise):
(
set +e
time ( set -e; false; echo no5; )
echo yes5 $?
)
And following succeeds under bash3 and does something completely different under bash4:
(
set -e
time { ( false; echo no7; ); echo yes6 $?; }
echo yes6 $?
)
Note that the "no" echo
es are not printed, while the "yes" are output by bash3 (but not all by bash4).
If you compare this with the subshell (...)
processing under set -e
it looks like the time
builtin is executed with the subshell context in the time (...)
case. WTF?
Tested with
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
outputs
real 0m0.000s
user 0m0.001s
sys 0m0.000s
yes0 1
yes3 1
yes5 1
yes6 1
real 0m0.000s
user 0m0.000s
sys 0m0.001s
yes6 0
and
GNU bash, version 4.1.5(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
outputs
real 0m0.001s
user 0m0.000s
sys 0m0.004s
yes0 1
yes5 1
Note that "yes3" and "yes6" cases show a huge difference in how bash3 and bash4 process set -e
.
But the "yes5" case is confusing. It looks like "time" somehow is processed by the subshell and not in the outer shell.
Is this behavior enforced by POSIX, is one of the bashs buggy or is it just a bash
special behavior?
Thanks ;)
PS: If you are puzzled why this is not academic: There once was a script running under set -e
("yes3" without time
). It was altered to log some timing information, the hack looks like "yes6". But now bash4 comes around and it needes a fix again.
Upvotes: 2
Views: 260
Reputation: 8398
Actually the behaviour in bash 4 is predictable,
set -e
will cause you to exit the current shell if any simple command in current shell or subshell of current shell returns a non-zero exit status (for a more elaborate/accurate description, read the Bash manual's section on set
)
set -e
takes precedence over time
, i.e. say in no2 case
(
set -e
time false;
)
You exit subshell before time
can finish executing, hence no output from time
.
With that in mind, what happens in the yes5 case (let's call the 1st ( )
as "subshell level 1", and the 2nd ( )
as "level 2")
(
set +e
time ( set -e; false; echo no5; )
echo yes5 $?
)
is when you encounter false
which returns exit status 1, the set -e
causes it to exit subshell level 2, this returns exit status 1 to subshell level 1. But since level 1 has set +e
, everything runs.
For yes6 case,
(
set -e
time { ( false; echo no7; ); echo yes6 $?; }
echo yes6 $?
)
the false
in subshell level 2 returns triggers set -e
, hence the absence of output.
The rest is left as an exercise for the reader.
Upvotes: 2