Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2817

trap を使ってシェルスクリプトの後処理を楽に制御する

$
0
0

シェルスクリプトは、その可搬性からビルドスクリプトやセットアップスクリプトに利用されることが多い。

今回は、後処理やシグナル処理使われる trap というコマンドを紹介する。

trap コマンドは、指定したシグナルを受信したときに実行するコマンドを設定できる。先に例を見せる。

long_sleep.sh
#!/bin/bashfunction trap_sigint(){echo"割込を検出"}trap trap_sigint sigint # 第2引数のsigint は int とも書けるecho"長考"sleep 100 # 長い処理echo"終了"

long_sleep.sh を実行している最中に Ctrl+Cを入力し SIGINT を送ると次のようになる。

$ bash long_sleep.sh
長考
^C割込を検出
終了

上記のコードには注意するべき点がある。それは 割込を検出と表示されたあと 終了と表示されている。つまり、 trap は実行中のコマンドに割り込んでいるだけで、後続の処理は実行される。

検証してみよう。

long_double_sleep.sh
#!/bin/bashfunction trap_sigint(){echo"割込を検出"}trap trap_sigint sigint # 第2引数のsigint は int とも書けるecho"長考"sleep 10 # 長い処理1sleep 10 # 長い処理2echo"終了"

このスクリプトは、2度 SIGINT を送らないと 終了と表示されない。

$bash long_double_sleep.sh
長考
^C割込を検出
^C割込を検出
終了

これを踏まえると、なんらかのシグナルを受け取ったとき後続処理を中止するためには trap で呼び出すスクリプトの中で終了させなければならない。

exit_when_interrupt.sh
#!/bin/bashfunction trap_sigint(){echo"割込を検出"exit 0 # exit status 0 は正常終了}trap trap_sigint sigint # 第2引数のsigint は int とも書けるecho"長考"sleep 10 # 長い処理1echo"後続処理"sleep 10 # 長い処理2echo"終了"

上記のように書けば後続処理は実行されず、 終了とも表示されない。
処理を確実に中止できる。

$bash src/trap.bash
長考
^C割込を検出

実践

例として、「一時ファイルを作成し、途中で SIGINT を受け取ったら一時ファイルを削除するスクリプト」を作る。

一時ファイルを作るときは、 mktemp を使うこと。詳しくは、 man mktempを参照。

postprocess.sh
#!/bin/bashset-efunction postprocess (){echo"作ったファイルを削除"rm-f$TMPFILE}trap signal_int int

TMPFILE=`mktemp`# see: http://tldp.org/LDP/abs/html/exitcodes.htmlfunction signal_int (){
    postprocess
    exit 130 # 128 + SIGINT}echo"一時ファイル">>$TMPFILEecho$TMPFILEcat$TMPFILEsleep 10 # 重い処理echo"最後まで終了"

途中で Ctrl + Cで SIGINT を送ってもファイルは削除される

$bash postprocess.sh                                         
/var/folders/0x/thnv3ql10dd6ksxsyy1wb6hh0000gn/T/tmp.GnpgZZi2
一時ファイル
^C作ったファイルを削除

$# ファイルが存在しないことを確認$ls-al /var/folders/0x/thnv3ql10dd6ksxsyy1wb6hh0000gn/T/tmp.GnpgZZi2
ls: /var/folders/0x/thnv3ql10dd6ksxsyy1wb6hh0000gn/T/tmp.GnpgZZi2: No such file or directory

Exit Status について

http://tldp.org/LDP/abs/html/exitcodes.htmlによれば、 bash の exit status (あるいは exit code とも呼ばれる) は一部予約されている。

正常終了は 0、一般的なエラーは 1、 致命的なエラーシグナルは シグナル値 + 128 で予約されている。

さきほどの後処理をするスクリプトでは、 SIGINT のシグナル値は 2 であるため、 130 という exit status を設定した。

ほかのシグナル値が気になる場合は、 man signalで調べると良い。

正常終了したときも一時ファイルを削除する

上記のスクリプトでは、割り込まれなかったときファイルが消されない問題があるのでさらに修正する。

postprocess2.sh
#!/bin/bashset-efunction postprocess (){echo"作ったファイルを削除"rm-f$TMPFILE}trap signal_int int
trap postprocess EXIT # 正常終了したときに後処理を実行TMPFILE=`mktemp`# see: http://tldp.org/LDP/abs/html/exitcodes.htmlfunction signal_int (){
    postprocess
    exit 130 # 128 + SIGINT}echo"一時ファイル">>$TMPFILEecho$TMPFILEcat$TMPFILEsleep 10 # 重い処理echo"最後まで終了"
$bash postprocess2.sh
/var/folders/0x/thnv3ql10dd6ksxsyy1wb6hh0000gn/T/tmp.r1e9Pr4G
一時ファイル
最後まで終了
作ったファイルを削除

$# ファイルが削除されていることを確認$ls-al /var/folders/0x/thnv3ql10dd6ksxsyy1wb6hh0000gn/T/tmp.r1e9Pr4G
ls: /var/folders/0x/thnv3ql10dd6ksxsyy1wb6hh0000gn/T/tmp.r1e9Pr4G: No such file or directory

重要な箇所は、 trap を使って exit というシグナルがきたときに postprocess を呼び出しているところである。 この exit は疑似シグナルと呼ばれるものの一つで、正常終了直前に送られる。詳細は man bashの trap の節を読むといい。疑似シグナルには、 EXIT のほかに DEBUG 、 ERR がある。


Viewing all articles
Browse latest Browse all 2817

Trending Articles