[Top][All Lists]

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

Re: parent trap EXIT appears to subshell but is not used

From: Robert Elz
Subject: Re: parent trap EXIT appears to subshell but is not used
Date: Tue, 30 Mar 2021 03:18:43 +0700

    Date:        Mon, 29 Mar 2021 17:31:23 +0200
    From:        Valentin Lab <valentin.lab@kalysto.org>
    Message-ID:  <604a4dab-afc5-cd5e-ee80-64d3dfb2ef35@kalysto.org>

  | In 4.3, this makes sense to me. EXIT trap is not available and not executed.
  | In >4.3, I don't understand: 'trap -p' is displaying a trap that is not
  | really enabled ?

Yes.   The reason is that there needs to be a way to discover what
the traps are set to, for which the standard method is
(or better, but newer, and doesn't yet work in every shell)
        traps=$(trap -p)

The problem is that the trap command there runs in a subshell environment.
In such an environment, all the (non-ignored) traps are reset to their
default values (as you observed in bash 4.3 ... and which still actually
happens in later versions) which would mean those commands would be useless.

It would still be possible to get the data, by using a temp file, or similar,
but that's ugly, and subject to leaving stray temp files around if the shell
is killed at an inconvenient time (and for the obvious reason, you cannot set
an EXIT trap to clean up in this case).

So, the standard specifically allows for the values of traps to be made
available from a subshell environment - the way that is explained to be
able to be done (not required) is bizarre, and hard to implement, so in
practice a simpler form is used ... all traps are nominally disabled (cannot
execute in the subshell environment) as is required, but their values aren't
changed until something changes a trap (and perhaps some other cases, which
can vary depending upon the shell implementation).   All that is actually
required is that if the first command (perhaps only command) in a cmdsub
subshell is a trap command which extracts the trap values (not sets any)
then that command should report the parent of the subshell's values, not
its own.   In practice there is no need to be quite so limited.   As soon
as any trap has been set (and often, in other cases too), all the others
must revert to the default values, and at that point, the trap(s) that have
now been set can execute when appropriate.

This should make no difference to any rational script - when a subshell
environment starts, we know all traps (for that subshell) are reset to the
default (ie: nothing), so there is no point ever enquiring about what they're
set to, or not until some of them have been changed.   Any enquiry before
that must intend to obtain the parent's trap settings (simply because asking
to be told what we already know is wasteful, and so, dumb.)

For all of this, there's no difference why the subshell environment was
created, the standard only requires it of command substitution subshells,
but to implement that the subshell execution code needs to be told why it
exists, which otherwise is irrelevant, so this is often done the same way
for all subshells.


ps: if the shell is implemented well, it is possible to do

        trap 'whatever' EXIT

to set an EXIT (or any other) trap, and then

        ( eval "$(trap -p EXIT)"; commands )

to copy the EXIT (in this case) trap setting from the parent to the
subshell.   If more traps are to be copied, they must all be done in
that same initial eval command (more signal names after, or instead of,
"EXIT"). This isn't required to work by POSIX, as the outer subshell there
can clear the traps before the eval is executed (and hence before its arg is
expanded, running the inner subshell for the command substitution) - so
while the command substitution subshell reports the EXIT trap value, it
is too late, as it has already been reset in its parent (the outer subshell).
That's poor.

reply via email to

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