web-dev-qa-db-ja.com

複数の同時コプロセスを持つことは可能ですか?

テストスクリプトのintent1 以下は、「外部」コプロセス(seq 3を実行)を開始し、このコプロセスからwhileループで読み取り、読み取られた行ごとに、外部ループの現在の反復を識別する行を出力します。 、「内部」コプロセスを開始し(seqを実行し、新しい引数を使用)、ネストされたwhileループでこの内部コプロセスから読み取り、この内部コプロセスをクリーンアップします。ネストされたwhileループは、内部コプロセスから読み取った各行の出力を出力します。

#!/bin/bash
# filename: coproctest.sh
PATH=/bin:/usr/bin

coproc OUTER { seq 3; }
SAVED_OUTER_PID="${OUTER_PID}"

exec {OUTER_READER}<&"${OUTER[0]}"
while IFS= read -r -u "${OUTER_READER}" OUTER_INDEX; do

    printf -- '%d\n' "${OUTER_INDEX}"

    START=$(( OUTER_INDEX * 1000000 ))
    FINISH=$(( START + OUTER_INDEX ))

    # (
      coproc INNER { seq "${START}" "${FINISH}"; }
      SAVED_INNER_PID="${INNER_PID}"
      exec {INNER_READER}<&"{INNER[0]}"

      while IFS= read -r -u "${INNER_READER}" INNER_INDEX; do
          printf -- '    %d\n' "${INNER_INDEX}"
      done

      exec {INNER_READER}<&-

      wait "${SAVED_INNER_PID}"
    # )

done
exec {OUTER_READER}<&-
wait "${SAVED_OUTER_PID}"

このスクリプトを実行すると、次の出力が得られます。

% ./coproctest.sh
1
./coproctest.sh: line 30: warning: execute_coproc: coproc [12523:OUTER] still exists
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect
2
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect
3
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect

コメント付きの2行のコメントを外すと、ほぼ同じ出力が得られます。


Q1:複数のコプロセスを同時に実行することは可能ですか?

Q2:もしそうなら、上記のスクリプトをどのように変更して、目的の出力を実現する必要がありますか?


1 私は最近コプロセスを使い始めたばかりですが、まだ理解できないことがたくさんあります。その結果、このスクリプトには、ほぼ間違いなく、正しくない、扱いにくい、または不要なコードが含まれています。回答のこれらの弱点についてコメントしたり、修正したりしてください。

3
kjo

bashマニュアルの最後にある「バグ」セクションから:

一度にアクティブなコプロセスは1つだけです。

5
Kusalananda

Q1:複数のコプロセスを同時に実行することは可能ですか?

@Kusalanandaが指摘しているように、Bash v4以降(現在のv5を含む)では、正式にはありません。

ただし、警告にもかかわらず動作する可能性があると言えますが、もちろん保証とYMMVはありません。 ここを参照 もう少し洞察を得てください。

Q2:その場合、目的の出力を実現するには、上記のスクリプトをどのように変更する必要がありますか?

might(上記のとおり)を修正すると、問題なく動作する可能性があります。

exec {INNER_READER}<&"{INNER[0]}"  # <-- lacks the '$' sign for the 'INNER[0]' variable

これにより:

./coproctest.sh: line 19: INNER_READER: ambiguous redirect

メッセージ、そしてその結果として:

./coproctest.sh: line 21: read: : invalid file descriptor specification

メッセージ。

それを修正して警告を脇に置いてしまえば、それは私にとってはうまくいきます。

その他の注意事項:

  • 子プロセス(サブシェルまたはコマンドまたはスクリプト)に渡す場合を除いて、coprocのファイル記述子を複製する必要はありません。
  • おそらく、seqコマンドが自然にすぐに終了し、自動変数が使用される前に消えてしまったためです。これまでと同じように行うことで、これらの重複ファイル記述子は後続のすべてのコマンドとバックグラウンドプロセスに継承されます。これは、コプロセスが実際に入力パイプを使用し、終了するために閉じられるのを待つ場合は望ましくない可能性があります。したがって、同期メカニズムによるアドレス指定の別のアプローチは、たとえば、OUTERコプロセスを{ seq 3; exec >&-; read; }にし、メインスクリプトからの入力を消費したときに、たとえば、 echo >&${OUTER[1]}; wait "${OUTER_PID}"は、コプロセスのreadを続行し、次にwaitを続行します。 $OUTER_PID変数が消える前に、waitが実行される保証はないことに注意してください。このような場合は、警告メッセージをミュート(または完全に無視)して、成功ステータスを強制することができます。 || true
  • 個人的な補足として、複数のコプロセスを同時に実行することに本当に決心している場合は、roughを再実装する可能性があることをお伝えします。バックグラウンドプロセスとcoproc名前付きFIFOでBashv3構文を使用するmkfifoに相当し、Linuxではmkfifosの代わりにプロセス置換を使用するトリックもあります。 Bash v4構文を使用すると、それほど複雑ではありませんが、それでも難しい演習になります。
2
LL3