無限ループの終了


52

コマンドが終了するたびに自動的に再実行したいので、次のようなコマンドを実行しました。

while [ 1 ]; do COMMAND; done;

しかし、私はループを止めることができないならばCtrl-cそれはちょうど殺すようCOMMANDループ全体をしていません。

同様のことをどのようにして達成できますか?端末を閉じることなく停止できますか?


11
bashを使用している場合は、Ctrl-Zを使用してジョブを停止し、「%1を強制終了」して強制終了します。
ポールCager

3
ちょっと待ってください... Linusは、「Linuxは素晴らしいことを知っています...それは5秒で無限ループを実行します。」 -本当に...あと数秒待って、完了するはずです。
lornix

@PaulCagerも私のために働いた!Ctrl-Cが機能しないのになぜ機能するのですか?
Ciro Santilli新疆改造中心法轮功六四事件14年

@cirosantilliは、外側のジョブ(bashの「ラッパー」)を殺します。状況によっては、すぐに「COMMAND」を強制終了しない場合があります。たとえば、バックグラウンドにすると、親が死んでいる場合でも、生き残っていることがあります。しかし、ループは死んでおり、それが重要な部分です。
オリオン14年

回答:


37

コマンドの終了ステータスを確認してください。コマンドがシグナルで終了した場合、終了コードは128 +シグナル番号になります。bashのGNUオンラインドキュメントから:

シェルの目的のために、ゼロの終了ステータスで終了するコマンドは成功しました。ゼロ以外の終了ステータスは失敗を示します。この一見反直感的なスキームが使用されているため、成功を示す明確に定義された方法と、さまざまな失敗モードを示すさまざまな方法があります。番号がNである致命的なシグナルでコマンドが終了すると、Bashは値128 + Nを終了ステータスとして使用します。

POSIXは、シグナルで終了するコマンドの値が128より大きいことも指定していますが、GNUのように正確な値を指定していないようです:

シグナルを受信したために終了したコマンドの終了ステータスは、128を超えると報告されます。

たとえば、control-Cでコマンドを中断した場合、終了コードは130になります。これは、UNIXシステムではSIGINTがシグナル2であるためです。そう:

while [ 1 ]; do COMMAND; test $? -gt 128 && break; done

9
これは保証されていないことに注意してください。実際、多くのアプリケーションはこれを行いません。
クリスダウン

1
@Kyle Jones:それについて言及しているPOSIX / GNUドキュメントにリンクできますか?
Ciro Santilli新疆改造中心法轮功六四事件14年

@cirosantilli完了。
カイルジョーンズ14年

@KyleJonesありがとう!まだ実際にはCOMMAND = paplay alert.oggで動作していません。おそらくpaplay信号を処理するためでしょうか?
Ciro Santilli新疆改造中心法轮功六四事件14年

@cirosantilliはい、それが理由です。プロセスがシグナルを処理して終了する場合、それは未処理のシグナルによって終了されるプロセスとは異なります。
カイルジョーンズ14年

48

ctrl+ を使用して、実行中のジョブを停止してバックグラウンドに置くことができますz。次に、次の方法でジョブを強制終了できます。

$ kill %1

[1]はジョブ番号です。


説明などについては、この回答も参照してください。
スキッピールグラングロウ14

2
この比較的最近の答えは単に機能します。投票する必要があります。+1
シヴァム

あなたは私をたくさん助けてくれました。これは私がこの質問で検索したものです:)
マクシミリアンルタ

18

無限ループをスクリプトに入れて、そこで信号を処理するのが最善かもしれません。これが基本的な出発点です。必要に応じて変更することをお勧めします。スクリプトは- (または)trapをキャッチするために使用し、コマンドを終了し(ここではテストとして使用しました)、終了します。ctrlcSIGTERMsleep

cleanup ()
{
kill -s SIGTERM $!
exit 0
}

trap cleanup SIGINT SIGTERM

while [ 1 ]
do
    sleep 60 &
    wait $!
done

4
いいね ここで私はautorestartingのnetcatをラッパーを作るためにこのヒントを使用方法は次のとおりです。trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
ダグラス

2
あなたは、この追加した場合trap、無限ループと同じ(bashの)スクリプトへのアプローチを殺害するために、使用$$の代わりに、$!(参照ここ
ardnew

15

私は一般的に押さえるだけCtrl-Cです。遅かれ早かれ、の間に登録されCOMMANDwhileループが終了します。おそらくもっと良い方法があります。


1
理由はわかりませんがpaplay、1sファイルのような特定のコマンドでは失敗します。
Ciro Santilli新疆改造中心法轮功六四事件14年

それは私のために働いた
アレクサンドル

これがすべてのソリューションの総当たりです。:/
マークロクサー


7

なぜ単純に、

while [ 1 ]; do COMMAND || break; done;

または、スクリプトで使用する場合、

#!/bin/bash
while [ 1 ]; do
  # ctrl+c terminates COMMAND and exits the while loop
  # (assuming COMMAND responds to ctrl+c)
  COMMAND || break
done;

1
非常にエレガントなソリューション。しかし、これはCOMMANDが常に成功の終了ステータスを返す場合にのみ機能しませんか?
ハワード

はい@howardh、それは正しいです。
デールアンダーソン

3

私は別の解決策を好む:

touch .runcmd; while [ -f ".runcmd" ]; do COMMAND; sleep 1; done

ループを終了するには、次のようにします。

rm .runcmd && kill `pidof COMMAND`

2
  1. PIDを使用していつでもプロセスを強制終了できます。端末を閉じる必要はありません。
  2. デーモンのような無限ループで何かを実行したい場合は、バックグラウンドに配置するのが最善です
  3. while : 無限ループを作成し、書き込みを保存します [ 1 ]

    while :; do COMMAND; done &

これにより、PIDが出力されます。を使用してプロンプトを終了するとctrl+d、バックグラウンドジョブは終了せず、後でどこからでもジョブを強制終了できます。kill PID

PIDを追跡できなくなった場合、pstree -pa $USERまたはpgrep -fl '.*PROCESS.*'を使用してPID を見つけることができます


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.