trap
は シグナル(INT
, TERM
など)や 擬似シグナル(EXIT
, ERR
, DEBUG
, RETURN
)を受け取った時に走らせるコマンド列を登録/解除するシェル組み込みです。
実務では一時ファイルの削除、優雅な終了、Ctrl+C 捕捉、失敗時のログ出力などに使います。
構文(Syntax)
# POSIX 互換(最小形)
trap [ARG] [SIGNAL ...]
# ARG : 受信時に実行するコマンド文字列(''なら無視、'-'なら既定動作に戻す)
# SIGNAL: HUP INT QUIT TERM EXIT など(名前/番号どちらでも可)
# bash/ksh 等の拡張
trap [-p] [ARG] [SIGNAL ...] # -p: 登録済みトラップの出力
trap -l # シグナル一覧(bash/ksh)
- 無視:
trap '' INT
(SIGINT
を無視) - 既定に戻す:
trap - INT
- 一覧:
trap -p
(登録中のみ)、trap -l
(番号と名前の対照)
SIGKILL
とSIGSTOP
は捕捉/無視できません。
主なオプション/指定子一覧
オプション/指定 | 説明 | 使用例 |
---|---|---|
SIGNAL 名/番号 | 対象シグナルを列挙。複数指定可。 | trap 'echo bye' TERM INT |
'' (空文字) | 受信しても何もしない(無視)。 | trap '' INT |
- | 既定動作へリセット。 | trap - INT |
EXIT | シェルが終了するときに実行。 | trap 'rm -f "$tmp"' EXIT |
ERR (bash等) | 直前のコマンドが非0で終了したとき。 | trap 'echo "ERR:$?"' ERR |
DEBUG (bash等) | 各コマンド実行前に実行(重い)。 | trap 'echo "$BASH_COMMAND"' DEBUG |
RETURN (bash等) | 関数や source が戻る時に実行。 | trap 'echo returning' RETURN |
-p (bash/ksh) | 現在のトラップを再設定可能な形で表示。 | trap -p |
-l (bash/ksh) | シグナル一覧を表示。 | trap -l |
ERR/DEBUG/RETURN
は POSIX 非標準。dash
などでは使えません。bash
でERR
を関数/サブシェルにも継承したい場合はset -E
を併用。
実行例
一時ファイルを確実に消す(EXIT トラップ)
説明: 正常/異常終了や set -e
でも最後に掃除します。
コマンド:
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
# ここで tmp を使う処理...
Ctrl+C(SIGINT)で優雅に終了
説明: 中断時にメッセージを出し、必要なら後処理も行います。
コマンド:
trap 'echo "Interrupted"; cleanup; exit 130' INT
cleanup() { echo "cleaning..."; }
while true; do sleep 1; done
終了コード/場所をログしてデバッグ(ERR)
説明: 失敗時にコマンドと行番号を記録(bash)。
コマンド:
set -Euo pipefail
trap 'echo "ERROR at ${BASH_SOURCE}:${LINENO}: ${BASH_COMMAND} (status=$?)"' ERR
danger() { false; }
danger # ← ここで ERR trap が発火
親スクリプト終了時に子プロセスをまとめて止める
説明: プロセスグループ全体に TERM
を送る(並列ジョブの後始末)。
コマンド:
trap 'echo "stopping"; kill 0' EXIT
long_job_a & long_job_b & wait
SIGTERM/SIGINT を同等に扱う
説明: 外部からの停止要求を捕捉して安全に中止。
コマンド:
trap 'echo "stopping..."; cleanup; exit 143' TERM INT
run_server
トラップを解除/確認する
説明: 解除・確認の基本。
コマンド:
trap - INT TERM # 既定動作に戻す
trap -p # 現在の登録内容を表示(bash/ksh)
trap -l # 利用可能なシグナル一覧(bash/ksh)
エラー例:捕捉不能なシグナル
説明: SIGKILL
は設定不可。
コマンド:
trap 'echo nope' KILL
出力例(例):
trap: KILL: bad trap
関連コマンド
kill
: プロセスへシグナル送信(自分自身へも送れる)。set
:-e/-E/-o pipefail
などと組み合わせてエラー処理を強化。wait
: バックグラウンドジョブの待機(trap
での後始末とセットで)。disown
(bash): ジョブをシェル管理から外す。tee
: ログを保存しつつ表示(ERR
罠と併用して診断に)。
備考
- クォートのコツ: ハンドラは単一引用符で囲み、実行時に展開したい変数だけ二重引用符にするのが安全(定義時展開を避けるため)。例:
trap 'echo "$LINENO"' ERR
。 - 終了ステータス:
EXIT
/ERR
ハンドラ内の"$?"
は直前のコマンドの終了コード。ハンドラのexit
が最終コードになります。 - 多重登録ではなく上書き: 同じシグナルに対して
trap
を再実行すると前の設定は上書きされます。連結したい場合は関数化して一つにまとめるか、自前で合成してください。 - サブシェル/関数での継承:
bash
ではERR
の継承にset -E
(またはset -o errtrace
)が必要。DEBUG
/RETURN
はset -o functrace
で継承対象を拡げられます。 - 非同期シグナル: トラップは次のプロンプトや安全な実行ポイントで走るため、実行タイミングに僅かな遅延があります。
- 移植性:
trap -l/-p
,ERR/DEBUG/RETURN
は移植性が低いので、POSIX 互換が要るスクリプトでは避けるか代替設計を。 - 捕捉不能:
SIGKILL
(9)とSIGSTOP
(19)は仕様上捕捉/無視できません。
参考
- POSIX
trap
仕様: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_28 - Bash マニュアル(The
trap
Builtin): https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-trap - Bash マニュアル(Signals): https://www.gnu.org/software/bash/manual/html_node/Signals.html
- Linux man-pages
signal(7)
(シグナル一覧): https://man7.org/linux/man-pages/man7/signal.7.html bash(1)
man(オプション-E
,errtrace
/functrace
など): https://man7.org/linux/man-pages/man1/bash.1.html
コメント