如何确定是否为BASH子外壳定义了EXIT陷阱?

时间:2019-08-15 19:20:26

标签: bash

下面是一个示例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陷阱?

更新1

此更新是针对用户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

1 个答案:

答案 0 :(得分:0)

使用Bash 3时

答案取决于您使用的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

此方法也适用于其他陷阱的子集。例如,此子集包括INTQUITTERMCHLD陷阱。但是,此子集不包括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,可以通过在功能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) )"