!!!技術的雑談-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 で殺しましょう。 [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 -- 初版 [[技術的雑談]]へ戻る !!突っ込み {{comment}} [[技術的雑談]]へ戻る {{trackback}} [[技術的雑談]]へ戻る