陷阱是由子shell继承的吗?

Bha*_*iya 17 shell trap subshell

我尝试了以下脚本:

#!/bin/bash
trap 'echo "touching a file" && touch $FILE' EXIT

foo1(){
        echo "foo1"
}
foo(){
        echo "foo"
        export FILE=${FILE:-/tmp/file1}
}
(foo1)
foo
Run Code Online (Sandbox Code Playgroud)

上述脚本的输出是:

[root@usr1 my_tests]# ./test.sh
foo1
foo
touching a file
Run Code Online (Sandbox Code Playgroud)

但是,我希望在退出时foo1也调用 trap ,这在子shell中调用。

  • 这是预期的吗?
  • 是否trap由子shell继承?
  • 如果是,那么在什么情况下trap由子shell继承?

Gil*_*il' 12

陷阱处理程序永远不会被子shell 继承。这是由 POSIX 指定的

进入子shell 时,未被忽略的陷阱将设置为默认操作。

请注意,忽略的信号 ( trap '' SIGFOO) 在子外壳中(以及外壳启动的外部程序中)仍然被忽略。

  • 在 bash 中,您可以 `set -E` 以便让子 shell 继承陷阱,但是要正确(至少以我的经验)真的很棘手。 (3认同)
  • 我不知道这是否适用于所有陷阱。我知道它适用于 ERR (2认同)

dos*_*ter 6

trap不会传播到子外壳,但某些方法允许子外壳报告父外壳的陷阱,而其他方法则不会。我用 bash 对 macos 做了一些测试。

GNU bash,版本 4.4.12(1)-release (x86_64-apple-darwin16.3.0):

trap 'echo hello' EXIT
trap # trap -- 'echo hello' EXIT
echo "$(trap)" # trap -- 'echo hello' EXIT
trap | cat # trap -- 'echo hello' EXIT
(trap) | cat # trap -- 'echo hello' EXIT
cat < <(trap) # empty
cat <<< "$(trap)" # empty
bash -c 'trap' # empty
trap & # trap -- 'echo hello' EXIT
Run Code Online (Sandbox Code Playgroud)

GNU bash,版本 3.2.57(1)-release (x86_64-apple-darwin16):

trap 'echo hello' EXIT
trap # trap -- 'echo hello' EXIT
echo "$(trap)" # trap -- 'echo hello' EXIT
trap > >(cat) # trap -- 'echo hello' EXIT
trap | cat # empty
(trap) | cat # empty
cat < <(trap) # empty
cat <<< "$(trap)" # empty
bash -c 'trap' # empty
trap & # empty
Run Code Online (Sandbox Code Playgroud)

很高兴知道这trap_output="$(trap)"将有助于捕获陷阱输出。如果除了trap >trap_output_file将其输出到文件(fifo 不起作用bash 3.2.57)然后用trap_output="$(<trap_output_file)"

fifo 将无法使用,bash 3.2.57因为它trap &为空bash 3.2.57但不bash 4.4.12

GNU bash,版本 4.4.12(1)-release (x86_64-apple-darwin16.3.0):

mkfifo /tmp/fifo; trap >/tmp/fifo & trap_output=$(</tmp/fifo); rm -f /tmp/fifo; echo "$trap_output"
# trap -- 'echo hello' EXIT

mkfifo /tmp/fifo; trap_output=$(</tmp/fifo) & trap >/tmp/fifo; rm -f /tmp/fifo; echo "$trap_output"
# empty because trap_output=$(</tmp/fifo) sets the variable in a subshell
Run Code Online (Sandbox Code Playgroud)

GNU bash,版本 3.2.57(1)-release (x86_64-apple-darwin16):

mkfifo /tmp/fifo; trap >/tmp/fifo & trap_output=$(</tmp/fifo); rm -f /tmp/fifo; echo "$trap_output"
# empty because trap >/tmp/fifo & is empty since it uses trap &

mkfifo /tmp/fifo; trap_output=$(</tmp/fifo) & trap >/tmp/fifo; rm -f /tmp/fifo; echo "$trap_output"
# empty because trap_output=$(</tmp/fifo) sets the variable in a subshell
Run Code Online (Sandbox Code Playgroud)


sch*_*ily 0

trap定义不会传播到子 shell。

验证方式:

trap "echo bla" 1 2 3

(trap)

  • 许多 shell 将“(trap)”作为特殊情况处理,以便子 shell 可以报告(但不实际使用)父 shell 的陷阱。所以这个测试并不总是可靠的。 (4认同)