Why trap didn't work in a pipeline Why trap didn't work in a pipeline shell shell

Why trap didn't work in a pipeline


I modified trap.sh to include the xtrace option.

#!/bin/bashset -xtrap 'echo trapped' EXITexit 0

Running trap.sh as a script produces

~ $ ./trap.sh | cat + trap 'echo trapped' EXIT + exit 0 + echo trapped trapped

Sourcing it first, however produces

~ $ . trap.sh | cat++ trap 'echo trapped' EXIT++ exit 0

This indicates that the trap is executed in a deeper subshell (why, I don't know), and that the trap itself is never executed (I confirmed in a second experiment by touching a file int he trap instead of just echoing, in case there was an issue with standard output being inherited; the file was never touched).

My guess is that somehow the EXIT signal is being ignored prior to the source command being executed, based on this sentence from the description of the trap command in the man page:

Signals ignored upon entry to the shell cannot be trapped or reset.

As a result, the trap command is executed, but the trap itself is never registered, and so does not fire.


Better change your test command to . trap.sh|cat (standard output from trap.sh couldn't be displayed with :). But even then there is no output, so you are right: the trap didn't work. This must be a bug in bash, and should be reported to the maintainers.

Interestingly, when we echo $$ from inside the script trap.sh, we see that it is executed by the same shell that executes the whole pipeline . trap.sh|cat, contradictory to the manual's statement: Each command in a pipeline is executed as a separate process (i.e., in a subshell). This was a fallacy, see comments. Perhaps this is related to some optimization to minimize subshell creation, but that's just speculation.


The command on the left hand side of a pipe is run in a subshell:

exit | grep

The exit sigtrap seems not to be propagated to subshells.

trap 'echo T >&2' EXIT ; (exit)    # Nothing.