bashで ctrl-C の検出をするには
bash でCtr-C の検出をする必要がある利用場面がある。たとえば、時間のかかる処理を書いていて途中で止めたいとか、スクリプトを作っていて中間ファイルを確実に消したいとか、Ctr-Cの強制終了で止めたときに「なにか処理」を実施したいことがったります。
trap を使う。
trap を使うことで実現ができる
#!/usr/bin/env bash trap 'echo Trapped; echo end' 2 sleep 10
trap にわたすのは、文字列ではなく「コマンド」
先の例であれば、文字列を渡していますが、正確には「コマンド(として実行できる文字)」を渡しています。
そのため、関数を作って次のようなこともできます。
#!/usr/bin/env/sh function on_signal_interrupt( ){ echo interrupted. shutdown ; } trap on_signal_interrupt 2 sleep 60
ありがちなミス。
trap を使おうとしてありがちなミスが次の例です。
trap で関数が登録する前に、時間のかかる処理を書いても当然実行されません。
#!/usr/bin/env bash sleep 10 ## ここで時間のかかる処理。→ Ctr-C trap 'echo Trapped; echo end' 2 # ←実行されない
ソースファイルにコードを追記するので、ついつい末尾に追加してやらかすことは結構あるので注意。
複数のシグナルをまとめてキャッチする。
trap "echo trapped " 1 2 3 4 5
まとめて書けばまとめてトラップしてキャッチできる。
まとめて書いても、どのシグナルか区別できない・・・
シグナルをまとめて受け取ったとしても、関数内でそれを区別できないっぽいです。
#!/usr/bin/env bash function on_siginal( ){ echo echo arguments is ... echo $@ echo signal_traoped } trap on_siginal 1 2 3 sleep 10
実行結果
takuya@Desktop$ bash signal_trap.sh ^C arguments is ... signal_traoped
まとめて受け取ってCASEで分岐出たら便利なのにね。できなさそう。
trap の使い方の調べ方
trap は、 シェルの組み込みコマンドなので、man ではなく、help で使い方を確認することができます。
takuya@Desktop$ help trap trap: trap [-lp] [[arg] signal_spec ...] シグナルまたは他のイベントをトラップします。 シェルがシグナルを受け取るか他の条件が発生した時に実行されるハンドラーを 定義および有効化します。 ARG はシグナル SIGNAL_SPEC を受け取った時に読み込まれ実行されるコマンド です。もし ARG が無い (かつシグナル SIGNAL_SPEC が与えられた場合) または `-' の場合、各指定したシグナルはオリジナルの値にリセットされます。 ARG が NULL 文字列の場合、各シグナル SIGNAL_SPEC はシェルにおよび起動さ れたコマンドによって無視されます。 もし SIGNAL_SPEC が EXIT (0) の場合、ARG がシェルの終了時に実行されます。 もし SIGNAL_SPEC が DEBUG の場合 ARG は単に毎回コマンドの前に実行されます。 もし SIGNAL_SPEC が RETURN の場合 ARG はシェル関数または . か source に よって実行されたスクリプトが終了した時に実行されます。 SIGNAL_SPEC が ERR の場合、-e オプションが有効な場合にシェルが終了するようなコマンド失敗が発 生するたびに実行されます。 もし引数が与えられない場合、 trap は各シグナルに割り当てられたコマンドの 一覧を表示します。 オプション: -l シグナル名とシグナル番号の対応一覧を表示します -p 各 SIGNAL_SPEC に関連づけられた trap コマンドを表示します 各 SIGNAL_SPEC は <signal.h> にあるシグナル名かシグナル番号です。シグ ナル名は大文字小文字を区別しません。また SIG 接頭辞はオプションです。 シグナルはシェルに対して "kill -signal $$" で送ることができます。 終了ステータス: SIGSPEC が無効か、無効なオプションを与えられない限り成功を返します。
wait: trap と合わせて知っておくと便利なBashの関数
そもそもTrapをどう使えばいいのか、疑問に思うこともあるけど、wait で他のプロセスを待ち合わせてるときとかに便利かもしれないですね。 wait のマニュアルはコチラ。
takuya@Desktop$ help wait wait: wait [-n] [id ...] ジョブの実行完了を待ち、終了ステータスを返します。 ID で識別される各プロセス (プロセスID または ジョブ指定) を待ち、その終了 ステータスを返します。ID が与えられない場合、現在アクティブな全ての子プ ロセスを待ち 0 を返します。ID がジョブ指定の場合ジョブのパイプラインに ある全てのプロセスを待ちます。 終了ステータス: 最後の ID の終了ステータスを返します。IDが無効であるか、無効なオプ ションが与えられた場合には失敗を返します。
シグナル一覧
シグナルは、man signal で一覧を見ることができる。
No Name Default Action Description 1 SIGHUP terminate process terminal line hangup 2 SIGINT terminate process interrupt program 3 SIGQUIT create core image quit program 4 SIGILL create core image illegal instruction 5 SIGTRAP create core image trace trap 6 SIGABRT create core image abort program (formerly SIGIOT) 7 SIGEMT create core image emulate instruction executed 8 SIGFPE create core image floating-point exception 9 SIGKILL terminate process kill program 10 SIGBUS create core image bus error 11 SIGSEGV create core image segmentation violation 12 SIGSYS create core image non-existent system call invoked 13 SIGPIPE terminate process write on a pipe with no reader 14 SIGALRM terminate process real-time timer expired 15 SIGTERM terminate process software termination signal 16 SIGURG discard signal urgent condition present on socket 17 SIGSTOP stop process stop (cannot be caught or ignored) 18 SIGTSTP stop process stop signal generated from keyboard 19 SIGCONT discard signal continue after stop 20 SIGCHLD discard signal child status has changed 21 SIGTTIN stop process background read attempted from control terminal 22 SIGTTOU stop process background write attempted to control terminal 23 SIGIO discard signal I/O is possible on a descriptor (see fcntl(2)) 24 SIGXCPU terminate process cpu time limit exceeded (see setrlimit(2)) 25 SIGXFSZ terminate process file size limit exceeded (see setrlimit(2)) 26 SIGVTALRM terminate process virtual time alarm (see setitimer(2)) 27 SIGPROF terminate process profiling timer alarm (see setitimer(2)) 28 SIGWINCH discard signal Window size change 29 SIGINFO discard signal status request from keyboard 30 SIGUSR1 terminate process User defined signal 1 31 SIGUSR2 terminate process User defined signal 2
参考資料
- http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html#sect_12_02_02
- man signal
- help trap