2

UNIX で実行されるプログラム (制御できない) があり、終了すると「正常に完了しました」と出力されますが、終了しません。プロセスがいつ終了したかを (コマンドの出力をチェックして) 自動的に検出して、プロセスを強制終了し、他のアクティビティを続行できるようにしたいと考えています。複雑なのは、これらのスクリプトを複数同時に実行できるようにしたいためです。(実行する必要があるアクティビティの 1 つは、さまざまな入力でスクリプトを呼び出す必要がありますが、スクリプトを実行するたびに戻るのに時間がかかるため、それらを並行して実行したいと考えています)

誰かがこれに似たようなことをしましたか? コマンドの stderr および stdout 出力を、ランダムなファイル名を持つ一時ファイルにリダイレクトし、ファイルを末尾にして、終了条件 (つまり、特定のログ行) を grep にパイプすることができます。問題は、確かに tail -f が実行され続けるため、決して終了しないことです。投票する必要がありますか?もしそうなら、最善のアプローチは何ですか?

4

7 に答える 7

2

投票する必要はありません。inotifywaitなどのinotifyツールを使用して、出力ファイルが変更されたことを検出し、それをgrepして、必要に応じてプロセスを強制終了できます。ハッピーハンティング!

于 2010-04-22T07:51:38.180 に答える
2

#!/usr/bin/expect

spawn /home/foo/myjob
expect "正常に完了"

于 2010-04-22T20:08:08.773 に答える
1

これが私の刺し傷です。かなりうまく機能しますが、killが呼び出されるたびにサブシェルスクリプト全体をエコーするkilledメッセージがコンソールに出力され、それを抑制することができないため、かなりスパムです。スパム性を取り除く方法が見つかったら更新します (ちなみに、stdout と stderr を /dev/null にリダイレクトしても効果はありません)。

注: これを実行するには bash4 が必要です。サブシェルではなく、親シェルの pid を提供するため、代替ではありません$BASHPID$$

!/bin/bash

for i in {1..8}; do
  (
    mypid=$BASHPID
    (
      #subshell to simulate started process
      sleep 2
      echo finished
      while : ; do
        :
      done
    ) | \
    {
      while read line; do
        if [[ $line == finished ]]; then
          break;
        fi
      done
      echo process done, killing $mypid...
      kill -9 $mypid
    }
  ) &
done
wait
于 2010-04-22T09:40:56.630 に答える
1

次のラッパー スクリプトは実際のコマンドを呼び出し、出力をteeにパイプして fifo に書き込みます。ラッパー スクリプトは、予想される文字列が fifo から検索されると、実際のコマンドを強制終了します。

#!/bin/bash

# cmd to run
expected_output=$1
shift
cmd=("$@")
# where to read commands output
mkfifo /tmp/killonoutput.$$
# start cmd async 
"${cmd[@]}"|tee /tmp/killonoutput.$$ 2>/dev/null &

if grep -q --max-count=1 "$expected_output" /tmp/killonoutput.$$;then
    kill %1 
    echo "Killed ${cmd[@]}" 
fi
# grep returned so fifo was closed
rm  /tmp/killonoutput.$$

実行例:

./killonoutput.sh "Finished" bash -c "echo sleeping;sleep 3;echo Finished; sleep 10000" 
sleeping
Finished
Killed bash -c echo sleeping;sleep 3;echo Finished; sleep 10000
./killonoutput.sh: line 17: 19553 Terminated              "${cmd[@]}"
     19554                       | tee /tmp/killonoutput.$$ 2> /dev/null
于 2010-04-22T16:40:10.590 に答える
0

これはbashにとってやり過ぎかもしれませんね。Pythonを使用している場合は、subprocessモジュールを使用して、独自のプログラムと子スクリプトの間で通信チャネルを開いたままにすることができます。さらに良いことに、threadingモジュールを使用して、子スクリプトの複数の実行を並行して開始できます。

スクリプトは、「正常に完了」を出力した後に何かを出力しますか?そうでない場合は、出力された最後のx文字をポーリングして(提案したようにランダムなファイルに、おそらくtail -n 1最後の行を取得するために使用して)、「正常に完了した」と表示されたかどうかを確認できます。ただし、スクリプトが後で印刷を続けると、行を見逃す可能性があります。

grepまたは、出力で「正常に完了」することもできます。

于 2010-04-22T07:51:58.080 に答える
0

最初に考えられる解決策:
your_program > tempfile1
grep -i "Completed successfully" tempfile1; もし [ $? -eq 0]; 次に i=`pidof your_program`; $i を殺します。フィ

まずはリダイレクトです。次に、grep の終了ステータスをチェックします。0 (成功) の場合は、プログラムの pid を取得して強制終了します。
これは「素早く考える」練習でした。それはうまくいくはずです。欠点は、プログラムのインスタンスを一度に 1 つしか実行できないことですが、もちろん、適応させることができ、並行して実行することもできます。

edit-27.05.2010:
2 番目の解決策:
tail --pid=`pidof your_program` -f -n0 tempfile1 | awk '/Completed/ {if ($1=="Completed") {system("i=`pidof your_program`; kill $i")}}' &

さて、この長い行では、もう loop/crontab は必要ありません。説明:
--pid=`pidof your_program` は、指定された PID が終了した後に末尾を無効にします。このようにして、プログラムが強制終了されると、テールも一緒に停止します。
-n0 は、tempfile1 内の他の "Completed" ステートメントを無視します (そのため、最初に tempfile1 を常に切り捨てることを心配する必要はありません)。
awk は、プログラムによってスローされた「Completed」ステートメントを検索し、その{system}部分がプログラムで kill を実行します。また、全体を背景にしているので、最後に を
忘れないでください。 楽しむ。&

于 2010-04-22T09:22:45.373 に答える
0

いくつかのランダムなアイデア。(1) それがあなたのプログラムであれば、より便利に完成度を示すように修正することができます。(2) プロセス リスト ( ps ax ) を見ると、「Completed」メッセージを出力しようとすると、I/O 待機に入ることがわかるはずです。(3) この目的のために疑似 tty が存在すると思います。一時ファイルをいじる必要なく、stdout を直接見ることができます。

于 2010-04-22T07:53:43.287 に答える