シグナルのキャッチ (シェルスクリプト)
[履歴] [最終更新] (2015/07/12 09:02:45)

概要

無限ループに陥ってしまったプロセスを強制終了させるためにはCtrl-Cやkillコマンドを利用しますね。このとき、プロセスにはシグナルというものが送られています。プロセスはシグナルの種類に応じて既定された処理を実行します。trapコマンドを用いると、各シグナル番号に対応する既定の処理を書き換えることができます。

trapコマンド

シグナルN1, N2, N3, ...を受けたときに実行するコマンドを指定することで、trapコマンド実行後からのシグナル受信時の挙動を書き換えます。

trap 'シグナルを受けたときに実行するコマンド' シグナル番号N1, N2, N3, ...

主なシグナルとサンプルコード

シグナル2

Ctrl-Cを押したときに送られるシグナルです。SIGINT (SIGnal INTerruput) とも。

sample.sh (実行注意!!!)

#!/bin/sh
trap ''  2 # ''は何もしない、つまりシグナルを無視するということ。

while :
do
    echo 'looping... (CAN NOT BE STOPPED BY Ctrl-C!!)'
    sleep 1
done

実行例 (killコマンドか何かでシグナル2以外を送って終了させてください)

$ sh sample.sh 
looping... (CAN NOT BE STOPPED BY Ctrl-C!!)
looping... (CAN NOT BE STOPPED BY Ctrl-C!!)
....

シグナル15

killコマンドを実行したときに送られるシグナルです。シグナル受信時のコマンドリストにexitを含めていることに注意してください。含めないとシグナル受信後、コマンドリストを実行した後、プロセスは終了せずに残りの処理を継続実行します。

sample.sh

#!/bin/sh
trap "echo 'killed'; exit" 15

while :
do
    echo 'looping...'
    sleep 1
done

実行例 (他のターミナルでkillコマンドを実行します)

$ sh sample.sh 
looping...
looping...
...
looping...
killed

別のターミナルでのコマンド例

$ ps | grep sample.sh  | awk '{print $1}' | xargs kill

なお、killコマンドはデフォルトではシグナル15を送りますが、kill -n pidとするとシグナルnを送れます。

シグナル0

シェルスクリプト内でexitが実行されたり、すべての処理が完了して終了した際に自分自身に送るシグナルです。

sample.sh

#!/bin/sh
trap "echo 'end'" 0
echo 128

実行例

$ sh sample.sh 
128
end

シグナル1 (関連情報)

ターミナル終了時にログインシェルによって送信されるシグナルです。こちらに記載した nohup という関連コマンドがあります。

関連ページ
    やりたいこと hello.sh #!/bin/sh while : do date sleep 1 done ローカルホストにおけるバックグラウンド処理はコマンドの後に '&' を付与することで実現できます。リダイレクションについてはこちらをご参照ください。 ./hello.sh > out.txt 2>&1 & tailf out.txt 2015年 6月 15日
    プロセスID関連 (ps, pgrep, pkill) 全プロセスを表示するためには ps ax とすればよく、その表示を見やすくするためには "u" と "w" を追加して ps auxw とすればよいです。表示件数自体は同じです。そのうち特定のコマンドのプロセスIDだけを表示したい場合は ps ax | grep 'my_script' | grep -v grep | aw
    値のセット/リセット VAR=128 # セット VAR= # リセット # unset VAR # リセットの別の方法 (変数の消去。unsetは関数の消去もできます) '='の左右に空白が入るとエラーになります。 sample.sh #!/bin/sh TODAY=`date` # TODAY = `date` # エラー echo "Date: `date`, TODAY"