web-dev-qa-db-ja.com

半非同期パイプ

次のパイプがあると仮定します。

a | b | c | d

cまたはbsh(またはbash)が完了するのを待つにはどうすればよいですか?つまり、スクリプトdはいつでも開始できます(そしてnotを待つ必要があります)が、正しく機能するにはcからの完全な出力が必要です。

使用例は、画像を比較するdifftoolgitです。これは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

私は解決策を見つけました、コメント(またはより良い解決策)は大歓迎です。

11
krlmlr
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
6
Hauke Laging

私があなたの質問を正しく理解していれば、これはうまくいくはずです:

a | b | c | { (exec <&3 3<&-; d) &} 3<&0

(fd 3のトリックは、一部の(ほとんどの)シェルがstdinを&で/ dev/nullにリダイレクトするためです)。

5

Bashでは、 プロセス置換 を使用できます。プロセス置換のコマンドは非同期で実行され、待機されません。

a | b | c > >(d)

これは、Haukeの入力の助けを借りて、試行錯誤によって私が見つけたものです。

a | b | { c; kill -PIPE $$; } | d

同等に:

a | b | ( c; kill -PIPE $$; ) | d

(パイプ内であれば{}はとにかくサブシェルで実行されるため、後者はより明示的です。)

他のいくつかの信号(QUITTERMUSR1など)も機能しますが、この場合、信号の説明は端末に表示されます。

これがPIPE信号の本来の意図なのだろうか。 マニュアル によると:

SIGPIPEPIPE信号は、プロセスがもう一方の端に接続されていない状態でパイプに書き込もうとすると、プロセスに送信されます。

つまり、パイプ信号を人為的にサブシェルに送信すると、通知なしで終了し、最終的なコンシューマー(d)はそのままになります。

これは、shbashの両方で機能します。

3
krlmlr

あなたはただ行うことができます:

a | b | c | (d ; cat > /dev/null)

したがって、dが終了すると、catは終了するまでcの残りの出力を吸収します。

OK。コメントの後、答えはバックグラウンドで直接dを開始することだと思います。

行う:

a | b | c | (d &)

または、stdinからのdの読み取りに問題がある場合は、Stephane Chazelasの解決策を使用します。

0
angus

「moreutils」パッケージのspongeプログラムを使用できます。

a | b | c | sponge | d

スポンジはcにパイプする前にdの出力の終わりを求めます。それがあなたが望んでいたことだといいのですが。

0
Minijackson