技術的雑談-ctrl-cをscript内で捕捉する
環境
GNU bash 2.05b(1)-release
目的
- スクリプト実行中にctrl+cを検出したい
- どんな終わり方をしても必ず実行する処理を加えたい
手段
trapコマンドを使います。
trapコマンドはshell script内でトラップが発生したときに実行したいscriptを設定するコマンドです。
書式
trap [-lp] [arg] [sigspec ...]
- -l
- signalの一覧を表示する
- -p
- 指定したsignalに関連付けられているscriptを表示する
- arg
- sigspecに関連付けるscriptを文字列で記述する。空文字列を指定するとそのsignalの補足を解除できる。何も指定しないとそのsignalに現在関連付けられているscriptを表示する。
- sigspec
- スペース区切りでsignalを列挙する。
signal
ちなみに、よく使うsignalはこんな感じ。
文字列で指定しても数字で指定しても良い。
- HUP (1)
- kill -HUPなどで呼ばれる。普通は「設定ファイルの読み直し」を実装するのがお約束。
- INT (2)
- インタラプト。ctrl+cで発生する。
- KILL (9)
- プロセスの強制終了。INTよりも強い。kill -KILLで発行できる。これが来たらプログラムは直ちに終了するのがお約束。trapコマンドで何を書いても無視される。
- TERM (15)
- 終了要求。trapで指定しても無視される。
使用例
#!/bin/sh trap 'echo "HUP"' HUP trap 'echo "INT"' INT trap 'echo "KILL"' KILL trap 'echo "TERM"' TERM trap 'echo "zero"' 0 while [ $EEE -eq 0 ] do echo '.' sleep 10 done exit 0
10秒ごとに「.」を1つ表示します。
ctrl+cでもkill xxxxでも死にません。(ある意味危険ですな。)
ctrl+c押したりkill -HUPやったりkill -KILLすると「INT」「HUP」「KILL」なんて表示して、そのシグナルが来たことを教えてくれます。
止めたいときは、ctrl+zで一時中断してから、
ps
でこのscriptのPIDを調べて、
kill -TERM <PID>
で殺しましょう。
[1]+ Killed ./test.sh
とか出てきます。ちと怖い。
応用
manなんかをよく読むと、実行中のddにkill -ALRMとかやると今までに転送終わったデータ量とか表示してくれた気がするんだけど……linuxのmanには見当たらないなぁ…。
USR1とかUSR2などのユーザシグナルがあり、ユーザが独自のシグナルを定義するためにリザーブしてある。
ちなみに、Unixなどの「マルチプロセスOS」で一番手軽にプロセス空間を越えてメッセージを伝えるのが「シグナル」だったりする。
(いや、これを聞いて「おお〜」とか感心するのは、「メモリー空間」とか分かっていないと無理だよね(汗))
注意
trapでINTやKILLを捕捉するscriptを書いた場合、trap処理が不要になった時点で、
tarp '' INT
などと書いておかないとctrl+cで殺せないscriptになってしまう。
止められて困る場所を過ぎたらtrap解除するようにしましょう。
(ま、kill -TERMはユーザプロセスで補足不可能なsignalなので最終的にはそれで殺せるけど危ないでしょ?^^;)
履歴
2005/10/06 -- 初版
技術的雑談へ戻る