BASHサブシェルに対してEXITトラップが定義されているかどうかを確認するには?

BASHサブシェルに対してEXITトラップが定義されているかどうかを確認するには?

以下は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

サブシェル0と1のコマンドはtrap -p EXIT >&2定義されたEXITトラップを表示しますが、このexithdl機能はサブシェル0が終了した後にのみ実行されます。exithdlシャットダウン後にサブシェル1が実行されないようにする方法はありますか?つまり、funこの関数がEXITトラップなしでサブシェル1を決定できるように、1つ以上のコマンドを追加することは可能ですか?

例では、EXIT トラップはサブシェル 0 に対して定義されていますが、サブシェル 1 では定義されていません。このtrap -p EXITコマンドは、両方のサブシェルで実行されたときにまったく同じ出力を表示します。したがって、trap -p EXIT特定のサブシェルにトラップがあるかどうかを確認するためには使用できないとします。私はtrap -p EXITコマンドが実行されたときにEXITトラップの存在を示すことを認めていますfunが、funが返されたときにEXITトラップが実行された場合は表示されません。私は何を逃したことがありませんか?

答え1

バッシュ3を使用する場合

答えは、使用しているbashのバージョンによって異なります。たとえば、私のMacにはmacOS High Sierraがデフォルトでインストールされています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
}

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。ただし、このサブセットにはその他の問題は含まれません。TERMCHLDHUP

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 >&2fun

#!/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) )"

関連情報