trap 是否由子 shell 继承?

trap 是否由子 shell 继承?

我尝试了以下脚本:

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

foo1(){
        echo "foo1"
}
foo(){
        echo "foo"
        export FILE=${FILE:-/tmp/file1}
}
(foo1)
foo

上述脚本的输出是:

[root@usr1 my_tests]# ./test.sh
foo1
foo
touching a file

然而,我期望在退出时也会调用 trap foo1,这是在子 shell 中调用的。

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

答案1

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

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

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

答案2

trap不会传播到子 shell,但某些方式允许子 shell 报告父 shell 的陷阱,而其他方式则不允许。我用 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

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

很高兴知道这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

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

答案3

trap定义不会传播到子 shell。

验证方式:

trap "echo bla" 1 2 3

(trap)

答案4

尽管trap在子 shell 中调用会显示父级的陷阱,但它们不会在子 shell 中执行。您可以在子 shell 中设置新的陷阱。

要测试这一点,请使用以下代码创建一个脚本,运行它并ctrl+ c

#!/usr/bin/bash
function sub { echo sub_before: `trap`; trap 'echo kill_sub; exit' SIGINT; echo sub_after: `trap`; while :; do sleep 1; done; }
function parent { echo parent_before: `trap`; trap 'pkill -2 -P $$; echo kill_parent; exit' SIGINT; echo parent_after: `trap`; sub & wait; }
parent

您将看到两个陷阱都被执行。

(bash 5.0.17)

相关内容