半非同期パイプ


11

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

a | b | c | d

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

ユースケースは、画像を比較するdifftoolためのgitものです。これは呼び出されgit、その入力(a | b | cパート)を処理して、比較の結果(パート)を表示する必要がありますd。呼び出し元は、aおよびに必要な入力を削除しますb。つまり、スクリプトから戻る前に、プロセスc(またはb)を終了する必要があります。一方、dユーザーの入力を待っているので、待つことができません。

結果をc一時ファイルに書き込んだり、FIFOをで使用したりできることはわかっていますbash。(ただし、FIFOが役立つかどうかはわかりません。)一時ファイルなしでこれを実現することは可能shですか?

編集

おそらく、信頼できる方法でc(またはb)プロセスのプロセスIDを見つけることができれば十分でしょう。次に、パイプ全体を非同期で開始し、プロセスIDを待つことができます。の線に沿った何か

wait $(a | b | { c & [print PID of c] ; } | d)

編集^ 2

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


が完了した後にのみ、出力のd処理を開始したいですか?それが来るので、各出力行の処理を開始したくないですか?ccd
terdon

@terdon:いいえ、d好きなときにいつでも開始cできますが、次に進む前に終了する必要があります。
krlmlr 2014

それは自己矛盾するようです、もしd好きなときに始めることができれば、あなたは正確に何を待っていますか?
terdon

@terdon:使用例を示すために拡張されました。
krlmlr 2014

dの出力を使用しない場合、パイプラインの一部cを構成しても意味がないようdです。ただしd、入力を使用する場合d、アプローチがすべての違いを生むために、入力をすべて読み取った後、しばらくの間その入力を処理する必要があります。
Hauke Laging 2014

回答:


6
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

ありがとう。しかし、その場合、中間出力用の一時ファイルを作成する方がより詳細で、(人間にとって)解析が簡単です。また、信号で競合状態を回避するにはどうすればよいですか?...私はよりクリーンな解決策を望んでいましたが、これが行く方法であるなら、そうしてください。
krlmlr 2014

@krlmlrどのような競合状態ですか?
Hauke Laging 14

notifyシグナルトラップを設定する前に実行される可能性があります。その信号を見逃さないようにするにはどうすればよいですか?
krlmlr 2014

@krlmlr trapが定義された後に送信されるシグナル自体を受信するまで、パイプラインを呼び出すスクリプトを停止します。
Hauke Laging 14

あなたの編集:パイプはループで呼び出され、その上で私は制御できません。残念ながら、{ c; bg; }または{ c; exit 0; }動作するようには思えません。
krlmlr 2014

5

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

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

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



3

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

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

同等に:

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

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

(を含むいくつかの他の信号QUITTERMおよびUSR1作業が、)も、しかしこの場合には信号の説明は、端末上で示されています。

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

SIGPIPEPIPEプロセスが他の端に接続されていない状態でパイプに書き込もうとすると、シグナルがプロセスに送信されます。

つまり、パイプ信号を人為的にサブシェルに送信すると、メッセージが表示されずに終了し、最終的なコンシューマ(d)はそのままになります。

これはとの両方shで機能しbashます。


0

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

a | b | c | sponge | d

スポンジは、c出力をパイプする前に、その出力の最後に使用しdます。それがあなたが望んでいたことを願っています。


0

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

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

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

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

行う:

a | b | c | (d &)

または、stdinからの読み取りに問題がある場合は、Stephane Chazelasのソリューションを使用してくださいd


私の使用例はむしろ逆の方法だと思います:はcより早く終了し、終了dするまで待つc必要がありますが、気にしませんd
krlmlr 2014

聞き取れませんでした。c終了しdてまだ実行しているときに何をしたいですか?殺すd
アンガス14

dGUIがあり、ユーザーが閉じるまで実行できます。
krlmlr 2014

OK ...しかし、これはすでに起こっています。、、および作業が完了するabc標準出力を閉じて終了します。d実行され続けるだけです。終了d時にバックグラウンドに送信しcますか?それですか?
アンガス

はい、d完了したらバックグラウンドに送信する必要がありますc
krlmlr 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.