2016-05-27 13 views
0

複数の子プロセスをバックグラウンドで実行し、その間にデータをパイプする必要があります。私はプロセスの一つがエラーを報告する場合に反応する必要があるため、スクリプトが終了すると、私は任意のそれらの残りを殺したいので、私は出口が期待通りに機能しない

trap cleanup EXIT 

cleanup() 
{ 
    echo "Cleaning up!" 
    pkill -TERM -P $$ 
} 

を追加し、私はラッパー関数を作成しました。 fdで終わるものは、FIFOパイプに接続された以前に開いたファイル記述子です。

run_gui() 
{ 
    "$GAME_BIN" $args <&$gui_infd >&$gui_outfd # redirecting IO to some file descriptors 
    if [[ $? == 0 ]]; then 
     echo exiting ok 
     exit $OK_EXITCODE 
    else 
     exit $ERROR_EXITCODE 
    fi 
} 

機能run_ai1(), run_ai2は類似しています。その後

run_ai1() 
{ 
    "$ai1" <&$ai1_infd >&$ai1_outfd 
    if [[ $? == 0 || $? == 1 || $? == 2 ]]; then 
     exit $OK_EXITCODE 
    else 
     exit $ERROR_EXITCODE 
    fi 
} 

run_ai2() 
{ 
    "$ai2" <&$ai2_infd >&$ai2_outfd 
    if [[ $? == 0 || $? == 1 || $? == 2 ]]; then 
     exit $OK_EXITCODE 
    else 
     exit $ERROR_EXITCODE 
    fi 
} 

私は、関数を実行して、必要な配管を行う

printinit 1 >&$ai1_infd 
printinit 2 >&$ai2_infd 
run_gui & 
run_ai1 & 
run_ai2 & 
while true; do 
    echo "Started the loop" 
    while true; do 
     read -u $ai1_outfd line || echo "Nothing read" 
     echo $line 
     if [[ $line ]]; then 
      echo "$line" >&$gui_infd 
      echo "$line" >&$ai2_infd 
      if [[ "$line" == "END_TURN" ]]; then 
       break 
      fi 
     fi 
    done 
    sleep $turndelay 
    while true; do 
     read -u $ai2_outfd line || echo "nothing read" 
     echo $line 
     if [[ $line ]]; then 
      echo "$line" >&$gui_infd 
      echo "$line" >&$ai1_infd 
      if [[ "$line" == "END_TURN" ]]; then 
       break 
      fi 
     fi 
    done 
    sleep $turndelay 
done 

GUIを閉じるボタンで閉じられている。すなわち$GAME_BIN終了するが、私は標準出力にexiting okメッセージを見ることができますが、 cleanup関数はまったく呼び出されません。私は、プロセスが殺されているが、exit $OK_EXITCODEを呼び出す前にcleanupへの手動呼び出しを追加する場合:とにかくループの実行

./game.sh: line 309: 9193 Terminated    run_gui 
./game.sh: line 309: 9194 Terminated    run_ai1 
./game.sh: line 309: 9195 Terminated    run_ai2 
./game.sh: line 309: 9203 Terminated    sleep $turndelay 

を、スクリプトは(exit $OK_EXITCODE)それが必要として、終了しません。 AIスクリプトは単純です:

#!/bin/sh 
while true; do 
    echo END_TURN 
done 

どこでも私のスクリプトにはwaitコールはありません。私は間違って何をしていますか?

おもしろいこと:jobs -prun_ai2 &の直後に電話すると、3ピッドが表示されます。一方、cleanup関数からこのコマンドを呼び出すと、出力は空になります。

さらに、sleep $turndelayプロセスはいつ終了しますか?子プロセスから呼び出されるプロセスではありません。

+0

aiプロセスはまだ子供ですか? (つまり、デタッチするために自分自身をフォークしていますか?そのようなものですか?)物事が実行されているとき、プロセスツリーはどのように見えますか? –

+0

いいえ、私はここに貼り付けたもの以外何もしていません。 – marmistrz

+0

psの出力をttyに制限しないでください。それは分離されたプロセスが欠けてしまうでしょう。 'ps faxww'を試して、あなたのスクリプトのツリーがどんなものか見てみましょう。私はあなたが自分自身を切り離しているので、あなたはどこか別の人のプロセスを見つけるだろう*他の*。 –

答えて

1

EXITトラップスクリプトが終了するとトラップが起動します。あなたの最上位スクリプトはここで終了していません。

run_*機能が実行されているサブシェル(バックグラウンドで実行中)から継承されないため、サブシェルの終了時にトリガーしません。

あなたが望むものは、あなたが手作業でやったことのほうが多分そうですが(やや間違っているようですが)。

$GAMEが終了したときにcleanup関数がrun_guiから呼び出されるようにします。このようなもの。

run_gui() { 
    "$GAME_BIN" $args <&$gui_infd >&$gui_outfd # redirecting IO to some file descriptors 
    ret=$? 
    cleanup 
    exit $ret 
} 

は、その後、あなたはcleanupbashで、それは、でも、サブシェルで$$以来、サブシェルでのご使用、ですます$$(の正しい値を取得することを確認する必要がありますだけ親プロセスのIDですが、信号のメインスクリプトにハンドラを設定し、run_guiが終了するときにメインスクリプトに信号を送ることで、より明示的にすることができます)。

1

私は、子プロセスによっていくつかの子プロセスが開始されていると思います。これを行う:別のウィンドウで、ps -ft pts/1またはあなたのttyが何であれ。確認します。

また、pkillをkill $(jobs -p)に変更し、それが機能するかどうかを確認してください。

+0

私は間違ったスクリプトを使用しました(私は自分の作業ディレクトリに2つあります)。私は問題の説明を更新しました。 – marmistrz

関連する問題