2017年12月9日土曜日

shell scriptでsignal handling (w/ trap)

ちょっとしたshell scriptを書いていると、Ctrl-Cでprocessを殺した時などに適当な処理をさせたいことがある。

例えば、gpioに出力するscriptを実行中にCtrl-Cを押下すると、タイミングによってはgpioに出力しっ放しになり、後からpinを調べてgpio write $PIN 0などと手作業で始末しなければならない。これはいかにも面倒なので、Ctrl-Cによる中断 (SIGINT)が発生した際に終了処理を行わせたくなる。

この目的を達成するために、shell builtin commandであるtrapが使える。ただし、trapの仕様 (受け付けるoptionの種類や数)がshellによって異なるので注意が必要。以下、bashにおける利用例を挙げる。

使い方


singalに対する処理を指定する


trap <commands> <signals>

<commands>にはdouble quotation (")で括ってcommandの羅列が指定できる。

<signals>にはSIGINTやSIGTERMなどが指定できる。bashのtrapでは、trap -pで指定できるsignalsのlistが表示される。1つの処理に対して複数のsignalsを指定できる。

例: SIGINT (Ctrl-C)とSIGTERMが発生した時にgpio 25番 (WiringPi)に0を出力して終了する

$ trap "gpio out 25 0; exit" SIGINT SIGTERM

signalを単に無視する


<commands>に"" (空文字列)を渡す。

trap "" <signals>

例: SIGINTを無視する

$ trap "" SIGINT

signal handlingをdefaultに戻す


<commands>に"-" (hyphen)を指定する。

trap - <signals>

例: SIGINTのsiginal handlingをdefaultに戻す

$ trap - SIGINT

※bashの場合は<commands>を省略しても同じ効果。

$ trap SIGINT

注意


* shebang (shell scriptの1行目)を/bin/bashにしておくこと
* trapはshell scriptで使う場合が殆どだが、その際、なるべく早い段階で設定しておくこと → trapによるsignal handlingが設定されていない状態で主たる処理が始まってしまう。

少し考えれば当たり前なのだが、なぜか最後にtrapを指定していたscriptがあったので敢えて注意を。

補遺


shellによるtrapの動作やoptionsの違いについて。

options

* bashのtrapのみ、-lや-pといったoptionを受け付ける
* zshのtrapは何もしない
* dash (Debian defaultの/bin/sh)のtrapではerror

書式


* bashやzshのtrapは、<signals>として例えば"SIGINT"もしくはSIG抜きの省略形"INT"のような名前、或いは対応する番号 (SIGINTは2)で指定する
* dashでは、"INT" (SIG抜き)或いは番号 (2)で指定する

出典


* man bash-builtins
* man zshbuiltins
* man dash


0 件のコメント:

コメントを投稿