web-dev-qa-db-ja.com

Bashスクリプトで終了コードをトラップする方法

私のbashコードには多くの出口点があります。終了時にクリーンアップ作業を行う必要があるため、トラップを使用して、次のような終了用のコールバックを追加します。

trap "mycleanup" EXIT

問題は異なる終了コードがあり、対応するクリーンアップ作業を行う必要があることです。 mycleanupで終了コードを取得できますか?

40
Dagang

$?を使用して終了コードを取得できると思います。

46
bmk

受け入れられた答えは基本的に正しいです、私は物事を明確にしたいだけです。

次の例はうまく機能します。

#!/bin/bash

cleanup() {
    rv=$?
    rm -rf "$tmpdir"
    exit $rv
}

tmpdir="$(mktemp)"
trap "cleanup" INT TERM EXIT
# Do things...

ただし、関数なしでインラインでクリーンアップを行う場合は、より注意する必要があります。たとえば、これは機能しません:

trap "rv=$?; rm -rf $tmpdir; exit $rv" INT TERM EXIT

代わりに、$rvおよび$?変数をエスケープする必要があります。

trap "rv=\$?; rm -rf $tmpdir; exit \$rv" INT TERM EXIT

$tmpdirをエスケープすることもできます。これは、トラップ行が実行されたときに評価され、tmpdirの値が後で変更されて予期した動作が得られない場合に評価されます。

編集: shellcheck を使用して、bashスクリプトを確認し、このような問題に注意してください。

46
Paul Tobias

EXITトラップを他の信号のトラップから分離する方が良いことがわかりました

トラップテストスクリプトの例...

umask 77
tmpfile=`tmpfile.$$`
trap 'rm -f "$tmpfile"' EXIT
trap 'exit 2' HUP INT QUIT TERM

touch $tmpfile
read -r input 

exit 10

一時ファイルはクリーンアップされます。ファイル終了値の10は保持されます!割り込みは、終了値2をもたらします

基本的に、EXITトラップで「exit」を使用しない限り、元の終了値を保持して終了します。

ASIDE:EXITトラップの引用に注意してください。これにより、スクリプトの有効期間中にクリーンアップする必要があるファイルを変更できます。削除しようとする前に$ tmpfileの存在をテストすることもよくあるので、スクリプトの開始時に設定する必要はなく、作成する前だけです。

6
anthony