trap – シグナル受信時や終了時に実行するハンドラを登録する(シェル組み込み)

制御(停止・再開・終了)
スポンサーリンク

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 '' INTSIGINT を無視)
  • 既定に戻す: trap - INT
  • 一覧: trap -p(登録中のみ)、trap -l(番号と名前の対照)

SIGKILLSIGSTOP捕捉/無視できません

主なオプション/指定子一覧

オプション/指定説明使用例
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/RETURNPOSIX 非標準dash などでは使えません。bashERR を関数/サブシェルにも継承したい場合は 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/RETURNset -o functrace で継承対象を拡げられます。
  • 非同期シグナル: トラップは次のプロンプト安全な実行ポイントで走るため、実行タイミングに僅かな遅延があります。
  • 移植性: trap -l/-p, ERR/DEBUG/RETURN は移植性が低いので、POSIX 互換が要るスクリプトでは避けるか代替設計を。
  • 捕捉不能: SIGKILL(9)と SIGSTOP(19)は仕様上捕捉/無視できません。

参考

スポンサーリンク
Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする

コメント