我尝试了以下脚本:
#!/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)