parent trap EXIT appears to subshell but is not used
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
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
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
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
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