'trap' compliency?

Denys Vlasenko vda.linux at googlemail.com
Tue Sep 22 22:26:47 UTC 2009


On Tuesday 22 September 2009 16:19, Cristian Ionescu-Idbohrn wrote:
> On Tue, 22 Sep 2009, Denys Vlasenko wrote:

> > I am just saying that making this happen requires
> > making code which actually MUST LIE. :(
> 
> Yes.  I do understand that, but...  The standard requires it.  bash
> and zsh are already lying.  bash subshells seem to inherit traps, but
> zsh seems not to.

bash does not.

# trap 'echo Ho' SIGWINCH
# (trap)
#


> Yes, I can workaround this by storing trap-lists in temporary files.
> But that puts some more load on the system when it is executed
> hundreds of times in a relatively short period of time: at boot.
> 
> Is there a way to store trap-lists in variables?

I was thinking about it. _That_ would be a sane way to retrieve traps:
a magic $TRAPS variable. sadly, that's not what standard says.

Actually, standard does not SAY that "trap" in subshell shall print
parent shell's traps. It only says that its output must have suitable form

===========================================
The shell shall format the output, including the proper use of quoting,
so that it is suitable for reinput to the shell as commands that achieve
the same trapping results. For example:
===========================================

but then, in the example (which is not supposed to be normative):

===========================================
save_traps=$(trap)
...
eval "$save_traps"
===========================================

it implies that.


> Alright.  I believe you.  Honest :)
> 
> > Thus, one needs "trap" command to lie (!) in order to achieve what
> > one wants.
> 
> True.  Trap started in a subshell $(trap) should report traps in the
> current shell.

How can it do that? What if some traps were added IN subshell?
As in this my example:

# trap 'echo Ho' SIGWINCH
# echo `trap 'echo Hi' SIGWINCH; trap; bash -c 'kill -WINCH $PPID'; sleep 1`
trap -- 'echo Hi' SIGWINCH Hi
#                          ^^ "new" trap triggered by kill -WINCH

With "trap 'echo Hi' SIGWINCH;" part deleted, next "trap" should report
current shell's traps, but with it, it reports subshell traps.
So WHAT exactly it should report?!

Here's what I'm getting without "inner" trap SIGWINCH cmd:

# echo `trap; bash -c 'kill -WINCH $PPID'; sleep 1`
trap -- 'echo Ho' SIGWINCH
#


> > trap "echo hello" SIGWINCH
> > echo `. unsuspecting_shell_script.sh`
> >
> > Whoever tries to use "trap" inside unsuspecting_shell_script.sh
> > code would get bogus results - it'll say that SIGWINCH is trapped
> > but it is not!
> 
> Are you sure?  The way you wrote it, unsuspecting_shell_script.sh is
> sourced in a subshell.  Should subshells inherit traps?

No. All of the following CMDs are subshells, and therefore
should not inherit traps ("cmd" may be an arbitrary
_sequence_ of shell constructs):

( cmd )
{ cmd; } &
... | cmd | ....
v=`cmd`

and therefore all of them should not inherit traps.


> > And it would be hard to express in C code:
> > basically, on entry to $() or `` (and _only_ in this case),
> > traps should be unset, but should not be forgotten -
> > "trap" cmd should still show these "ghost" traps.
> 
> Well, I didn't look at the code, but I believe bash/zsh implement
> $(trap) as an exception to the `...`/$(...) rule, and run it in the
> context of the current shell (not a subshell).

Well, that's not easy, since `xxx` may be much more complex than that...

bash behavior is weirder than I thought:

# trap
trap -- 'echo Ho' SIGWINCH
# (trap)
# true | trap
# echo `true | trap`
trap -- 'echo Ho' SIGWINCH
# echo `true | (trap)`
trap -- 'echo Ho' SIGWINCH
#


Sigh.

I'm leaning towards special-casing `xxx` or $(xxx) which contains exactly
one word, "trap".

--
vda


More information about the busybox mailing list