日付を出力してリモートマシンにpingを実行するためのループを備えた簡単なbashスクリプトを作成しました:
#!/bin/bash
while true; do
# *** DATE: Thu Sep 17 10:17:50 CEST 2015 ***
echo -e "\n*** DATE:" `date` " ***";
echo "********************************************"
ping -c5 $1;
done
ターミナルから実行すると、 Ctrl + Cで停止できません。 。
^ Cを送信しているようです ターミナルに接続しますが、スクリプトは停止しません。
MacAir:~ tomas$ ping-tester.bash www.google.com
*** DATE: Thu Sep 17 23:58:42 CEST 2015 ***
********************************************
PING www.google.com (216.58.211.228): 56 data bytes
64 bytes from 216.58.211.228: icmp_seq=0 ttl=55 time=39.195 ms
64 bytes from 216.58.211.228: icmp_seq=1 ttl=55 time=37.759 ms
^C <= That is Ctrl+C press
--- www.google.com ping statistics ---
2 packets transmitted, 2 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 40.887/59.699/78.510/18.812 ms
*** DATE: Thu Sep 17 23:58:48 CEST 2015 ***
********************************************
PING www.google.com (216.58.211.196): 56 data bytes
64 bytes from 216.58.211.196: icmp_seq=0 ttl=55 time=37.460 ms
64 bytes from 216.58.211.196: icmp_seq=1 ttl=55 time=37.371 ms
何度押しても、どれだけ速く押しても。止められません。
テストをして、自分で実感してください。
副次的な解決策として、 Ctrl + Zで停止します 、それはそれを停止し、次にkill %1
。
ここで^Cで正確に何が起こっているのか ?
承認された回答:
何が起こるかというと、両方のbash
およびping
SIGINT(bash
を受け取る ない インタラクティブ、両方のping
およびbash
スクリプトを実行したインタラクティブシェルによって端末のフォアグラウンドプロセスグループとして作成および設定されたものと同じプロセスグループで実行します。
ただし、bash
現在実行中のコマンドが終了した後でのみ、そのSIGINTを非同期的に処理します。 bash
現在実行中のコマンドがSIGINTで終了した場合にのみ、そのSIGINTを受信したときに終了します(つまり、その終了ステータスは、SIGINTによって強制終了されたことを示します)。
$ bash -c 'sh -c "trap exit\ 0 INT; sleep 10; :"; echo here'
^Chere
上記、bash
、sh
およびsleep
Ctrl-Cを押すとSIGINTを受け取りますが、sh
通常は0の終了コードで終了するため、bash
SIGINTを無視するため、「ここ」が表示されます。
ping
、少なくともiputilsからのものは、そのように動作します。中断されると、統計情報が出力され、pingが応答されたかどうかに応じて、0または1の終了ステータスで終了します。したがって、ping
中にCtrl-Cを押すと 実行中、bash
Ctrl-C
を押したことに注意してください SIGINTハンドラー内ですが、ping
以降 正常に終了します、bash
終了しません。
sleep 1
を追加した場合 そのループでCtrl-C
を押します sleep
sleep
のため、実行中です SIGINTには特別なハンドラーがないため、終了してbash
に報告します。 SIGINTで死亡したこと、その場合はbash
終了します(親に中断を報告するために、実際にはSIGINTで自殺します)。
理由についてbash
そのように振る舞いますが、よくわかりません。振る舞いが常に決定論的であるとは限らないことに注意してください。 bash
で質問しました 開発メーリングリスト(更新 :@Jillesは、彼の回答に理由を突き止めました。
私が見つけた他の唯一のシェルはksh93です(@Jillesが言及しているように、更新、FreeBSD sh
も同様です。 )。そこでは、SIGINTは明らかに無視されているようです。そしてksh93
コマンドがSIGINTによって強制終了されるたびに終了します。
bash
と同じ動作をします 上記だけでなく:
ksh -c 'sh -c "kill -INT \$\$"; echo test'
「テスト」を出力しません。つまり、待機していたコマンドがSIGINTで終了した場合、たとえそれ自体がそのSIGINTを受信しなかったとしても、(そこでSIGINTで自分自身を強制終了することによって)終了します。
回避策は、次を追加することです:
trap 'exit 130' INT
スクリプトの上部でbash
を強制します SIGINTを受信すると終了します(いずれの場合も、SIGINTは同期的に処理されず、現在実行中のコマンドが終了した後にのみ処理されます)。
理想的には、SIGINTで死亡したことを親に報告したいと思います(そのため、別のbash
たとえば、そのbash
のスクリプト スクリプトも中断されます)。 exit 130
を実行する SIGINTで死ぬことと同じではありません(ただし、一部のシェルは$?
を設定します どちらの場合も同じ値になります)が、SIGINTによる死亡を報告するためによく使用されます(SIGINTが2であるシステムで最も多い)。
ただし、bash
の場合 、ksh93
またはFreeBSDsh
、それは機能しません。その130の終了ステータスは、SIGINTによる死亡とは見なされず、親スクリプトはしません。 そこで中止します。
したがって、おそらくより良い代替策は、SIGINTを受け取ったときにSIGINTで自殺することです:
trap '
trap - INT # restore default INT handler
kill -s INT "$$"
' INT