Re: exit in traps

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

 



On Fri, Oct 25, 2024 at 01:51:28AM +0200, Christoph Anton Mitterer wrote:
> Not sure whether this is a bug:
>    #!/bin/sh

>    #trap -- "echo EXIT" EXIT
>    trap -- 'echo $?; echo INT; exit' INT

>    foo=$(exit 44)
>    read -r tmp

> Running that and <Ctrl-C>ing at the read prompt:
> $ dash x.sh ; echo $?
> ^C1
> INT
> 1
> $ 

> $ bash x.sh ; echo $?
> ^C44
> INT
> 0
> $ 

> First, shouldn’t dash’s echo $? give 44, like bash’s does? The most
> recent pipeline is foo=$(exit 44), as the read hasn't completed yet, so
> $? should be 44.

The read has completed, exiting on SIGINT. According to the text in XCU
2.11 Signals and Error Handling, the shell shall not execute the trap
action until a foreground utility has completed. Only special builtins
are excluded from the definition of "utility" and "wait" has a special
case here, and read is neither. It is more common in the POSIX shell
that the difference between non-special builtins and external programs
are to be minimized.

So the value of $? printed by the trap action shall be greater than 128,
and passing it to kill -l shall result in INT.

Perhaps people could deviate from this by saying that the trap action is
executed after the utility completes but before the pipeline (containing
only that utility in this case).

Note that the special case for "wait" is not restricted to signals that
have a default action of terminating the process. So, for example, if a
trap on WINCH has been set, a received SIGWINCH shall interrupt "wait"
but not "read". This might not be as intended.

> Second, for the final exit state:
> POSIX says[0] for `exit`:
> > If n is not specified, the result shall be as if n were specified
> > with the current value of the special parameter '?' (see 2.5.2
> > Special Parameters ), except that if the exit command would cause the
> > end of execution of a trap action, the value for the special
> > parameter '?' that is considered "current" shall be the value it had
> > immediately preceding the trap action.

> I'd read that as if a blank `exit` in a trap action (but only one that
> actually causes the trap to end (i.e. not something like $(exit) ),
> should cause an overall exit status of 44 here, too.

> Both, dash and bash would do that wrong.

I agree with that, except that the value of $? needs to be as above,
greater than 128.

In FreeBSD sh I tweaked this a bit more, making the shell send the
signal to itself, so it is easier to implement such logic (something
like kill -INT $$ will not work in a subshell).

In ksh93, the initial value of $? is as above (258 in this case), but
the exit status is still 44, which I do not understand.

> If one uncomments the trap on EXIT:
> $ dash x.sh ; echo $?
> ^C1
> INT
> EXIT
> 1

> Which I don't understand either.
> IMO the INT trap should need to end with 44 here (but only because of
> the literal exit - I think it should rather end with 0 if there were
> not exit in it).
> But then, dash executes the EXIT action, and in that the original $?
> should be 44, too, (from the INT action’s exit, not directly from
> outside the trap actions) but why does the shell end with 1? Shouldn't
> it be 0 because of echo EXIT?

As documented in XCU 2.14 Special Built-In Utilities trap, the value of
$? after the trap action completes shall be the value it had before it
was invoked. So the "echo EXIT" shall not affect the final exit status,
and I think that behaviour is more useful: this way, exit statuses from
the outer script are preserved without the trap action needing to do
anything special. A trap action can invoke "exit" if it wants to replace
the script's exit status.

-- 
Jilles Tjoelker




[Index of Archives]     [LARTC]     [Bugtraq]     [Yosemite Forum]     [Photo]

  Powered by Linux