次のパイプがあると仮定します。
a | b | c | d
c
またはb
でsh
(またはbash
)が完了するのを待つにはどうすればよいですか?つまり、スクリプトd
はいつでも開始できます(そしてnotを待つ必要があります)が、正しく機能するにはc
からの完全な出力が必要です。
使用例は、画像を比較するdifftool
のgit
です。これはgit
によって呼び出され、その入力を処理し(a | b | c
部分)、比較の結果を表示する必要があります(d
部分)。呼び出し元は、a
およびb
に必要な入力を削除します。これは、スクリプトから戻る前に、プロセスc
(またはb
)を終了する必要があることを意味します。一方、d
はユーザー入力を待っているため、待つことはできません。
c
の結果を一時ファイルに書き込むか、bash
でFIFOを使用できることはわかっています。 (ただし、FIFOが役立つかどうかはわかりません。)sh
に一時ファイルがなくてもこれを実現できますか?
[〜#〜]編集[〜#〜]
おそらく、c
(またはb
)プロセスのプロセスIDを信頼できる方法で見つけることができれば十分でしょう。次に、パイプ全体を非同期で開始し、プロセスIDを待つことができます。の線に沿った何か
wait $(a | b | { c & [print PID of c] ; } | d)
EDIT ^ 2
私は解決策を見つけました、コメント(またはより良い解決策)は大歓迎です。
a | b | { c; [notify];} | d
通知は、例えば行うことができます。環境変数で渡されたPIDへのシグナル(kill -USR1 $EXTPID
)またはファイル(touch /path/to/file
)。
別のアイデア:
次のプロセス(開始を待機できるプロセス)をパイプラインから実行します。
a | b | { c; exec >&-; nextprocess;} | d
または
a | b | { c; exec >&-; nextprocess &} | d
私があなたの質問を正しく理解していれば、これはうまくいくはずです:
a | b | c | { (exec <&3 3<&-; d) &} 3<&0
(fd 3のトリックは、一部の(ほとんどの)シェルがstdinを&
で/ dev/nullにリダイレクトするためです)。
Bashでは、 プロセス置換 を使用できます。プロセス置換のコマンドは非同期で実行され、待機されません。
a | b | c > >(d)
これは、Haukeの入力の助けを借りて、試行錯誤によって私が見つけたものです。
a | b | { c; kill -PIPE $$; } | d
同等に:
a | b | ( c; kill -PIPE $$; ) | d
(パイプ内であれば{}
はとにかくサブシェルで実行されるため、後者はより明示的です。)
他のいくつかの信号(QUIT
、TERM
、USR1
など)も機能しますが、この場合、信号の説明は端末に表示されます。
これがPIPE
信号の本来の意図なのだろうか。 マニュアル によると:
SIGPIPE
:PIPE
信号は、プロセスがもう一方の端に接続されていない状態でパイプに書き込もうとすると、プロセスに送信されます。
つまり、パイプ信号を人為的にサブシェルに送信すると、通知なしで終了し、最終的なコンシューマー(d
)はそのままになります。
これは、sh
とbash
の両方で機能します。
あなたはただ行うことができます:
a | b | c | (d ; cat > /dev/null)
したがって、d
が終了すると、cat
は終了するまでc
の残りの出力を吸収します。
OK。コメントの後、答えはバックグラウンドで直接d
を開始することだと思います。
行う:
a | b | c | (d &)
または、stdinからのd
の読み取りに問題がある場合は、Stephane Chazelasの解決策を使用します。
「moreutils」パッケージのsponge
プログラムを使用できます。
a | b | c | sponge | d
スポンジはc
にパイプする前にd
の出力の終わりを求めます。それがあなたが望んでいたことだといいのですが。