どーも!marusukeです!
スクリプトが特定の状態で終了したときに、決まった処理を実行させるコマンドtrapについて説明します!
trapコマンドでできること
trap [アクション] [シグナルまたは条件...]
trapは、シェルスクリプトが特定のシグナルを受け取ったとき、または特定の終了状態になったときに、指定したコマンドを実行するための組み込みコマンドです。よく使われるのは次の4つです。
| 指定 | 発火するタイミング |
|---|---|
EXIT | スクリプトが(正常・異常を問わず)終了するとき |
ERR | 何かのコマンドが失敗(終了コード0以外)したとき |
INT | Ctrl+C(SIGINT)が送られたとき |
TERM | killコマンドなどでSIGTERMが送られたとき |
自動化スクリプトでは、一時ファイルの削除やロックの解放をEXITに登録しておくことで、途中でエラーが起きても片付けが漏れないようにするのが定番の使い方です。
trapコマンドの使用例
1. スクリプト終了時に一時ファイルを削除する
#!/bin/bash
TMPFILE=$(mktemp)
trap 'rm -f "$TMPFILE"' EXIT
echo "作業データ" > "$TMPFILE"
# ここで何らかの処理を行う
EXITに登録しておくと、スクリプトが最後まで正常に実行された場合はもちろん、途中でexitしたり、後述のERRでスクリプトを止めた場合でも、一時ファイルの削除処理が必ず実行されます。
2. コマンドが失敗した箇所を記録する
#!/bin/bash
set -e
trap 'echo "エラーが発生しました(行番号: $LINENO)" >&2' ERR
cp /path/to/source /path/to/dest
ERRに登録しておくと、set -eでスクリプトが止まる直前に、失敗した行番号などの情報をログに残せます。自動化スクリプトは人が画面を見ているとは限らないので、「どこで失敗したか」を残しておけるのは大きなメリットです。
3. Ctrl+Cによる中断時にメッセージを出す
trap 'echo "処理を中断しました"; exit 130' INT
INT(Ctrl+C)を捕捉して、中断時に独自のメッセージを表示してから終了する例です。130は「SIGINTで終了した」ことを示す慣例的な終了コードです。
4. 複数のシグナルをまとめて指定する
trap 'cleanup' EXIT INT TERM
同じアクションを複数のシグナル・条件に対してまとめて登録することもできます。cleanupという関数を1つ定義しておき、どの終わり方をしても同じ後片付け処理を呼び出す、という書き方はよく使われます。
5. 登録済みのtrapを確認・解除する
trap -p # 現在登録されているtrapの一覧を表示
trap - EXIT # EXITに登録した処理を解除する
主なオプション
| オプション | 説明 |
|---|---|
-p | 現在設定されているtrapの一覧を表示する |
- (アクションを省略) | 指定したシグナルの処理を解除し、デフォルトの動作に戻す |
補足:
ERRトラップはset -e(errexit)とほぼ同じ条件で発火します。if文の条件式の中や、&&・||でつないだコマンド、!を前置きしたコマンドが失敗した場合には発火しない点に注意してください。「思ったよりERRが呼ばれない」と感じたときは、まずこの条件を疑ってみてください。
関連コマンド
cronによる多重起動対策にはflockコマンドの使い方もあわせてご覧ください(一時ファイルを安全に作るmktempコマンドとの組み合わせ例は、mktempの記事公開後にこちらへ追記予定です)。
まとめ
trapは、スクリプトの終了時やシグナル受信時に決まった処理を実行させるためのコマンドです。特にEXITへの登録は、一時ファイルの削除やロックの解放を確実に行うために自動化スクリプトへ入れておく価値があります。
以上です! ここまで読んでいただきありがとうございました!
https://marusuke-blog.com/linux-command-flock/
https://marusuke-blog.com/linux-command-crontab/

コメント