下面是一个 BASH 脚本示例。
#!/bin/bash
exithdl() {
echo "in exithdl subshell=$BASH_SUBSHELL" >&2
}
trap exithdl EXIT
fun() {
echo "in fun subshell=$BASH_SUBSHELL" >&2
trap -p EXIT >&2
echo "returned from fun"
}
echo "subshell=$BASH_SUBSHELL" >&2
trap -p EXIT >&2
echo "$(fun)" >&2
echo "exiting" >&2
执行时会产生以下输出。
subshell=0
trap -- 'exithdl' EXIT
in fun subshell=1
trap -- 'exithdl' EXIT
returned from fun
exiting
in exithdl subshell=0
子 shell 0 和 1 中的命令trap -p EXIT >&2
显示定义的 EXIT 陷阱,但该exithdl
函数仅在子 shell 0 退出后执行。有没有办法确定exithdl
subshell 1退出后不会执行?换句话说,是否可以添加一个或多个命令,fun
以便此函数可以确定子 shell 1 没有 EXIT 陷阱?
在示例中,为子 shell 0 定义了 EXIT 陷阱,但没有为子 shell 1 定义。该trap -p EXIT
命令在两个子 shell 中执行时显示完全相同的输出。因此,我假设trap -p EXIT
不能用于检查特定子 shell 是否存在陷阱。我承认该trap -p EXIT
命令在执行时显示了 EXIT 陷阱的存在fun
,但如果当 fun 返回时 EXIT 陷阱将执行,则不会显示。我错过了什么吗?
答案1
使用 Bash 3 时
答案取决于您使用的 bash 版本。例如,我的 Mac 安装了 macOS High Sierra,默认情况下使用GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
.在这种情况下,可以通过在trap -p EXIT >&2
function 中的命令中添加括号来解决该问题fun
,如下所示。
#!/bin/bash
exithdl() {
echo "in exithdl subshell=$BASH_SUBSHELL" >&2
}
trap exithdl EXIT
fun() {
echo "in fun subshell=$BASH_SUBSHELL" >&2
(trap -p EXIT >&2) # <--- See Here
echo "returned from fun"
}
echo "subshell=$BASH_SUBSHELL" >&2
trap -p EXIT >&2
echo "$(fun)" >&2
echo "exiting" >&2
如下所示的结果输出不再将函数显示fun
为具有EXIT
陷阱。
subshell=0
trap -- 'exithdl' EXIT
in fun subshell=1
returned from fun
exiting
in exithdl subshell=0
此方法也适用于其他陷阱的子集。例如,此子集包括、和INT
陷阱QUIT
。但是,此子集不包括和其他陷阱。TERM
CHLD
HUP
使用 Bash 4 和 5 时
我还在 VirtualBox 中安装了 Ubuntu 18 和 19。这些操作系统默认分别使用GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
和GNU bash, version 5.0.11(1)-release (x86_64-pc-linux-gnu)
。当执行具有上述更改的脚本时,结果与原始输出相同。但是,对于这些较新版本的 bash,可以通过在 function 中的trap
命令之前添加一个命令来解决该问题,如下所示。trap -p EXIT >&2
fun
#!/bin/bash
exithdl() {
echo "in exithdl subshell=$BASH_SUBSHELL" >&2
}
trap exithdl EXIT
fun() {
echo "in fun subshell=$BASH_SUBSHELL" >&2
trap -- KILL # <--- See Here
trap -p EXIT >&2
echo "returned from fun"
}
echo "subshell=$BASH_SUBSHELL" >&2
trap -p EXIT >&2
echo "$(fun)" >&2
echo "exiting" >&2
选择该trap -- KILL
命令是因为KILL
陷阱无法更改。这会产生与上图相同的输出。此方法也适用于其他陷阱。
结论
如果您想exitTrap
为用于定义当前陷阱的命令设置一个变量(例如 )EXIT
,请使用下面所示的脚本。这应该适用于 bash 3、4 和 5。
trap -- KILL
exitTrap="$( (trap -p EXIT) )"