Unexpected sh behavior with EXIT trap and errexit

Maxim Khitrov max at mxcrypt.com
Tue Dec 27 23:00:32 UTC 2011


On Tue, Dec 27, 2011 at 4:36 PM, Devin Teske <devin.teske at fisglobal.com> wrote:
>> -----Original Message-----
>> From: owner-freebsd-questions at freebsd.org [mailto:owner-freebsd-
>> questions at freebsd.org] On Behalf Of Maxim Khitrov
>> Sent: Tuesday, December 27, 2011 12:25 PM
>> To: FreeBSD
>> Subject: Unexpected sh behavior with EXIT trap and errexit
>>
>> Can anyone explain this behavior (FreeBSD 9.0-RC3 amd64):
>>
>> Script:
>> ----
>> #!/bin/sh
>>
>> cleanup()
>> {
>>     echo 'first'
>>     echo 'second'
>> }
>>
>> fail() { return 42; }
>>
>> trap cleanup EXIT
>> set -o errexit
>> fail
>> ----
>>
>> Output:
>> ----
>> first
>> ----
>>
>
> If you change to:
>
> fail() { false; }
>
> Then the outcome is what you expect (both lines come out).

It seems that any command other than return, built-in or external,
works as expected.

> ASIDE: It appears that it's nothing to do with echo, stdout, or anything other than the fact that only the first command of the cleanup routine is called.

Correct, I used echo just for the example. I also tried 'set +o
errexit' as the first line of cleanup() to see if that would allow
execution to continue. Nope.

> From sh(1) regarding errexit:
>
> "If a shell function is executed and its exit status is explicitly tested, all commands of the function are considered to be tested as well."
>
> The exact meaning of which escapes me at the moment, but I'm lead to believe that this explanation somehow plays a role in what we're witnessing with your sample.

I don't know if this is related, but it means that errexit should not
cause the following code to terminate (and it doesn't):

dosomething()
{
    echo 'here'
    false
    echo 'still here'
}

set -o errexit
dosomething || true
echo 'all is well'

> It may be a bug, it may not. What's interesting in the sample is that the "return 42" is a valid command that succeeds while the function itself does not.
>
> HTH,
> Devin
>
>
>> Now comment out 'set -o errexit', replace 'fail' with 'fail || exit'
>> (which should be equivalent to using errexit), and run again.
>>
>> Output:
>> ----
>> first
>> second
>> ----
>>
>> Am I doing something stupid or is this a bug? Bash prints out the same
>> (second) output for both versions of the code.
>>
>> - Max


More information about the freebsd-questions mailing list