テストスクリプトの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 私は最近コプロセスを使い始めたばかりですが、まだ理解できないことがたくさんあります。その結果、このスクリプトには、ほぼ間違いなく、正しくない、扱いにくい、または不要なコードが含まれています。回答のこれらの弱点についてコメントしたり、修正したりしてください。
bash
マニュアルの最後にある「バグ」セクションから:
一度にアクティブなコプロセスは1つだけです。
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
coproc
名前付きFIFOでBashv3構文を使用するmkfifo
に相当し、Linuxではmkfifo
sの代わりにプロセス置換を使用するトリックもあります。 Bash v4構文を使用すると、それほど複雑ではありませんが、それでも難しい演習になります。