bashでスクリプトを書いていると、一時ファイルを作成したくなることがあります。
スクリプトが何の異常もなく、最初から最後まできちんと実行された場合には、
後処理として一時ファイルを削除すればいいわけですが、
実行エラーやCtrl-C等で強制終了したときなど、一時ファイルが削除されず残ってしまう場合があります。
サンプルスクリプト
#!/bin/bash
tmpfile=tmp.$$
echo "test tmp file" > $tmpfile
echo "wait for 5 seconds..."
sleep 5
rm $tmpfile
echo "clean tmp file($tmpfile)"
実行結果(正常)
$ ./test.sh
wait for 5 seconds...
clean tmp file(tmp.18758)
$ ls tmp.*
ls: cannot access tmp.*: No such file or directory
実行結果(Ctrl-cで強制終了)
$ ./test.sh
wait for 5 seconds...
^C
$ ls tmp.*
tmp.19196
*nixでは、特定のイベントが発生するとプロセスに対してシグナルを発行します。
例えばスクリプト実行中にCtrl-Cで強制終了したときにも、内部的には実行プロセスに対して
シグナルが発行されています。
bashではtrapコマンドを利用することで、受け取ったシグナルに対し、ハンドラを定義することができます。
ハンドラ内で一時ファイルを削除する処理を定義すれば、異常終了時にも対応できちゃいます。
サンプルスクリプト(シグナルハンドラ実装版)
#!/bin/bash
tmpfile=tmp.$$
trap "echo 'clean tmp file($tmpfile)'; rm $tmpfile; exit 1" 0
echo "test tmp file" > $tmpfile
echo "wait for 5 seconds..."
sleep 5
実行結果(正常終了)
$ ./test.sh
wait for 5 seconds...
clean tmp file(tmp.19457)
$ ls tmp.*
ls: cannot access tmp.*: No such file or directory
実行結果(Ctrl-Cで強制終了)
$ ./test.sh
wait for 5 seconds...
^Cclean tmp file(tmp.19498)
$ ls tmp.*
ls: cannot access tmp.*: No such file or directory
シグナルの仕組みに関する詳細は他に任せるとして、
trapコマンドの末尾にはシグナル番号を記載します。
シグナル番号0は擬似シグナルと呼ばれる特別なシグナルで、
スクリプトが終了するタイミングで発行されるので汎用的に使えます。
これで、気づいたら一時ファイルが量産されていたなんてことも回避できますね。