FreeBSDの/bin/shで、他実装とは違うヘンな挙動を見つけたのでメモ書き。
まずは、このテストコード(setm_test.sh)を書いてください。
setm_test.sh
#! /bin/sh
set -m # ←コレをつけると不可解な動きをする
# 終了時のトラップ設定
exit_trap() {
trap INT
echo "EXIT_TRAPPED"
exit 1;
}
trap 'exit_trap' INT
# メインルーチン(sleepを実行して終了を通知する)
sleep 5 || echo $?
echo "FINISH_SLEEPING"
trap INT
冒頭に出てくる-m
というオプションは、ジョブ制御を有効にするためのものです。具体的には、
- ジョブ完了メッセージ(“
[1] Done
”のようなメッセ^時)が出る。(非対話のシェルスクリプトのデフォルトでは表示されない) - fgコマンドのような、ジョブ制御コマンドが使えるようになる。(非対話のシェルスクリプトのデフォルトでは、エラーメッセージが出て使えない)
などの効果があります。
書いたら実行してみください。
(1)起動するだけで何もせず、終了を待つ。
$ sh setm_test.sh
FINISH_SLEEPING
$
5秒経過したらFINISH_SLEEPING
と表示されて終了します。
(2)起動したら5秒以内に[CTRL]+[C]を押して止める
CentOS6,Ubuntu14,AIX7.1で試した場合
$ sh setm_test.sh
^CEXIT_TRAPPED
$
FreeBSD10で試した場合
$ ./setm_test.sh
^C130
FINISH_SLEEPING
$
なんとOSによって挙動が変わります。FreeBSD以外だと、シェルが[CTRL]+[C]によるSIGINTを受け取ると、現在実行中のsleepコマンドを中断させ、trap設定してあったexit_trap関数へ制御を移します。
ところが、FreeBSDだと、sleepコマンドを中断させた後、そのままメインルーチンを続行してしまうのです。これっておかしくないでしょうか?
シェルではなくOSの問題?それとも仕様?
この問題、bashでも起こります。
FreeBSD10で試した場合
$ bash setm_test.sh
^C130
FINISH_SLEEPING
$
shだけで起こるならshのバグと思えそうですが、シェルを替えても起こるのでOSのバグなのか、それともFreeBSDの仕様なのか。
どちらなのか、現状では判断がつきません。(Macとかどうかなのかな?)
心当たりの方、是非コメントください。