Date: Mon, 29 Mar 2021 17:31:23 +0200 From: Valentin Lab <valentin....@kalysto.org> 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.