下面是一个示例BASH脚本。
#!/bin/bash
exithdl() {
echo "in exithdl subshell=$BASH_SUBSHELL" >&2
}
fun() {
echo "in fun subshell=$BASH_SUBSHELL" >&2
trap -p EXIT >&2
echo "returned from fun"
}
echo "subshell=$BASH_SUBSHELL" >&2
trap exithdl EXIT
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
子外壳0和1中的trap -p EXIT >&2
命令显示了已定义的EXIT陷阱,但是exithdl
函数仅在子外壳0退出后才执行。是否有办法确定子外壳1退出后exithdl
将不会执行?换句话说,是否有我可以添加到fun
的命令,以便此函数可以确定子外壳1没有EXIT陷阱?
此更新是针对用户suspectus的评论。
在以下示例中,函数fun
定义了与子外壳0中定义的相同的EXIT陷阱。
#!/bin/bash
exithdl() {
echo "in exithdl subshell=$BASH_SUBSHELL" >&2
}
fun() {
echo "in fun subshell=$BASH_SUBSHELL" >&2
trap exithdl EXIT
trap -p EXIT >&2
echo "returned from fun"
}
echo "subshell=$BASH_SUBSHELL" >&2
trap exithdl EXIT
trap -p EXIT >&2
echo "$(fun)" >&2
echo "exiting" >&2
执行后,将产生以下输出。在这里,退出每个子Shell会使函数exithdl
执行。
subshell=0
trap -- 'exithdl' EXIT
in fun subshell=1
trap -- 'exithdl' EXIT
in exithdl subshell=0
returned from fun
exiting
in exithdl subshell=0
答案 0 :(得分:0)
答案取决于您使用的bash版本。例如,默认情况下,安装了macOS High Sierra的Mac使用GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
。在这种情况下,可以通过在函数trap -p EXIT >&2
中的命令fun
上添加括号来解决问题,如下所示。
#!/bin/bash
exithdl() {
echo "in exithdl subshell=$BASH_SUBSHELL" >&2
}
fun() {
echo "in fun subshell=$BASH_SUBSHELL" >&2
(trap -p EXIT >&2) <--- See Here
echo "returned from fun"
}
echo "subshell=$BASH_SUBSHELL" >&2
trap exithdl EXIT
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
和其他陷阱。
我还在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,可以通过在功能trap
中的命令trap -p EXIT >&2
之前添加fun
命令来解决此问题,如下所示。
#!/bin/bash
exithdl() {
echo "in exithdl subshell=$BASH_SUBSHELL" >&2
}
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 exithdl EXIT
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) )"