简体   繁体   中英

Why trap didn't work in a pipeline

In this script We have a script trap.sh

#!/bin/bash
trap "echo trapped" EXIT
exit 0

and test.sh. If test.sh is like

#!/bin/bash
. trap.sh

or

#!/bin/bash
./trap.sh | :

trap works

But if test.sh is like

#!/bin/bash
. trap.sh | :

the trap didn't work.

Anybody know why is this?

Better change your test command to . trap.sh|cat . 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 . trap.sh|cat , contradictory to the manual's statement: Each command in a pipeline is executed as a separate process (ie, 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.

I modified trap.sh to include the xtrace option.

#!/bin/bash
set -x
trap 'echo trapped' EXIT
exit 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 touch ing 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM