parent trap EXIT appears to subshell but is not used

2021-03-29 Thread Valentin Lab

Hi,

I have encountered an issue when running some bash code from 4.3 that 
behave in an unexpected way on 4.4 or 5 ... I've managed to pinpoint the 
exact issue on my end.


Here is the code:


## 
trap -- 'echo bar' EXIT
(
  echo -n 'Subshell TRAP EXIT: '
  trap -p EXIT
  echo
)
echo main shell

##


Runnning this will give the same output on bash 4.4 and 5:

##  BEGIN OUTPUT
Subshell TRAP EXIT: trap -- 'echo bar' EXIT

main shell
bar
##  END OUTPUT


But will give this output on bash 4.3:

##  BEGIN OUTPUT
Subshell TRAP EXIT:
main shell
bar
##  END OUTPUT


We notice 2 important point:
- Bash >4.3 trap's is displaying parent shell's EXIT trap, while
  4.3 is not displaying it.
- None of them will execute any trap at the end of the subshell.


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 ?


Notice that we can set an EXIT trap in the subshell, and then all bash 
version will display AND execute the trap at the end of the subshell. 
Which seems totally okay to me.



Is this strange behavior about bash >4.3 being able to display EXIT 
trap, but won't use them is expected ? I'd be happy to know about the 
rationale behind this if this is expected.



Many thanks,

Valentin Lab


PS: note that I found some other 'report' of that behavior here: 
https://unix.stackexchange.com/questions/282722#answer-374269




parent trap EXIT appears to subshell but is not used

2021-03-29 Thread Oğuz
29 Mart 2021 Pazartesi tarihinde Valentin Lab 
yazdı:

> Hi,
>
> I have encountered an issue when running some bash code from 4.3 that
> behave in an unexpected way on 4.4 or 5 ... I've managed to pinpoint the
> exact issue on my end.
>
> Here is the code:
>
>
> ## 
> trap -- 'echo bar' EXIT
> (
>   echo -n 'Subshell TRAP EXIT: '
>   trap -p EXIT
>   echo
> )
> echo main shell
>
> ##
>
>
> Runnning this will give the same output on bash 4.4 and 5:
>
> ##  BEGIN OUTPUT
> Subshell TRAP EXIT: trap -- 'echo bar' EXIT
>
> main shell
> bar
> ##  END OUTPUT
>
>
> But will give this output on bash 4.3:
>
> ##  BEGIN OUTPUT
> Subshell TRAP EXIT:
> main shell
> bar
> ##  END OUTPUT
>
>
> We notice 2 important point:
> - Bash >4.3 trap's is displaying parent shell's EXIT trap, while
>   4.3 is not displaying it.
> - None of them will execute any trap at the end of the subshell.
>
>
> 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 ?
>
>
> Notice that we can set an EXIT trap in the subshell, and then all bash
> version will display AND execute the trap at the end of the subshell. Which
> seems totally okay to me.
>
>
> Is this strange behavior about bash >4.3 being able to display EXIT trap,
> but won't use them is expected ? I'd be happy to know about the rationale
> behind this if this is expected.


I think it is. Otherwise `exit_trap=$(trap -p exit)' wouldn't work.


>
>
> Many thanks,
>
> Valentin Lab
>
>
> PS: note that I found some other 'report' of that behavior here:
> https://unix.stackexchange.com/questions/282722#answer-374269
>
>

-- 
Oğuz


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

2021-03-29 Thread Robert Elz
Date:Mon, 29 Mar 2021 17:31:23 +0200
From:Valentin Lab 
Message-ID:  <604a4dab-afc5-cd5e-ee80-64d3dfb2e...@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
traps=$(trap)
(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.

kre

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.





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

2021-03-29 Thread Oğuz
29 Mart 2021 Pazartesi tarihinde Robert Elz  yazdı:

> Date:Mon, 29 Mar 2021 17:31:23 +0200
> From:Valentin Lab 
> Message-ID:  <604a4dab-afc5-cd5e-ee80-64d3dfb2e...@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
>

The same goes for the job table right? None of ash derivatives (including
netbsd sh) seems to do that right though. `( sleep 3 & ( sleep 1 & wait )
)' hangs for three seconds instead of one, which doesn't happen on other
shells.


-- 
Oğuz


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

2021-03-31 Thread Robert Elz
Date:Tue, 30 Mar 2021 07:33:08 +0300
From:=?UTF-8?B?T8SfdXo=?= 
Message-ID:  


  | The same goes for the job table right?

Yes, though there's no posix explanation for that (no expectation
there that code would ever want to examine it).

  | None of ash derivatives (including
  | netbsd sh) seems to do that right though. `( sleep 3 & ( sleep 1 & wait )
  | )' hangs for three seconds instead of one, which doesn't happen on other
  | shells.

This is fixed in the current NetBSD sh, it waits for 1 second there, just
as if the job table was immediately cleared in the sub-shell.   I forget now
just how long ago that fix was installed, or if it got pulled up to the
netbsd-9 branch (ie: whether it can be expected in a reasonably up to date
9_STABLE version of sh).

Hmm - I just checked, that was fixed years ago, the fixed version should be
in NetBSD 8.1 and anything later (but not 8.0 or earlier) ("later" includes
everything netbsd 9 and more recent).

kre