それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

bashでCtrl-Cなどシグナルをトラップ(検出)して終了時の処理を書く

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

参考資料