
bash の trap で書く後始末と終了コード
結論 trap は渡した文字列を登録し、発火した時点でコードとして読み直す。単引用符なら変数は発火時の値になり、二重引用符なら張った時点の値が構文の一部として埋まる EXIT trap が発火するのはシェルの終了時で、張った関数の中ではない。その関数の local 変数はもう無いので、値は printf -v q '%q' で埋めるか、グローバル変数に置く EXIT trap は SIGINT・SIGTERM・SIGHUP で止められても走り、SIGKILL では走らない。trap cleanup EXIT INT と INT も並べると、Ctrl-C の後もスクリプトが先へ進む trap はシェルに 1 つの表で、関数ごとの範囲を持たない。ライブラリの trap - EXIT は呼び出し元の EXIT trap も消し、関数で張った RETURN trap は呼び出し元の return でも発火する set -e の下では、EXIT trap の中の失敗が終了コードを書き換え、trap の残りの行を飛ばす。set -u だけなら trap は止まるが、終了コードは残る 以下は GNU bash 5.3.20 / Linux x86_64 で実測した。 前提: trap は「後で読み直す文字列」をシェルの表に登録する trap '<文字列>' EXIT は、その場では何も実行しない。文字列をシェルの表に登録し、発火したときに新しいコマンドとして読み直す。 表はシェル (プロセス) に 1 つで、シグナル (EXIT・RETURN を含む) ごとに 1 本の文字列を持つ。同じシグナルに張り直すと、前の文字列は置き換わる 登録した文字列は trap -p <シグナル> で読める 張った時点と発火した時点では、変数の値も、呼び出し中の関数も、表の中身も変わりうる。以下の罠はどれもこのずれから起きる set -e 自体の効き方は bash の set -e が効かない場所と効きすぎる場所 に、 ERR trap がパイプの失敗で発火しない件は trap コマンドは pipe と併用すると動作しない に書いた。 ...