
たとえば、私の質問を明確にする必要があります。この動作は私にとって意味があります。
$ echo hi | cat
hi
$ echo hi | tee >(cat)
hi
hi
最初のケースは明らかです。 2番目のケースでは、コマンド置換を使用して「hi」をteeにパイプします。一方の「hi」はtee
「d」で印刷され、もう一方の「hi」は「cat
配送パイプ」で印刷されます。tee
これまではそんなに良くなった…
しかし、この場合、最初の「hi」はどうなりますか?
$ echo hi | tee >(echo yo)
yo
戻りコードは141で、パイプラインが失敗しました。原因は何ですか?
私は基本的な端末アプリケーションでMac OSX El Capitain、bashを実行しています。
答え1
私はあなたの経験を他の人が再現できるものに調整する方法を見つけたと思います。
$(エコハロー;スリップ1;エコワールド)Tシャツ>(猫) こんにちは こんにちは ...そしてしばらくして、 世界 世界 $エコ「$?」 0 $(エコハロー;スリップ1;エコワールド)Tシャツ>(エコヨ)| エヤディヤ こんにちは $エコ「$?」 141
理解できるように、実行中のプロセスのパイプを作成します。>(command)
command
。標準入力はcommand
コマンドライン(この場合)の他のコマンドは、開いて書き込むことができるtee
パス名に接続します。いつcommand
はいcat
、プロセスはそこに座ってEOFを取得するまでstdinから読み込みます。この場合、tee
標準入力から読み取られたすべてのデータは問題なくパイプに書き込まれます。
しかし、時command
はいecho yo
、プロセスはyo
標準出力に書き込まれ、すぐに終了します。これにより問題が発生しますtee
。もう一方の端にプロセスがないパイプに書き込むと、SIGPIPE シグナルを受け取ります。
明らかに、OS Xバージョンはtee
最初にコマンドラインにファイルを書き込み、次に標準出力にファイルを書き込みます。したがって、あなたの例(echo hi | tee >(echo yo)
)では、tee
パイプは最初の書き込みで失敗します。ただし、Linux および Cygwin のバージョンはtee
標準出力に書き込みます。最初hi
だから、死ぬ前に画面に書き込むことができます。私の拡張例では、パイプtee
に書き込むときにhello
死んで読んで書く機会はありませんworld
。
答え2
何が起こっているかを可視化するには、次の2つのバリエーションを比較します。
bash -c 'echo hi | tee >(sleep 1; echo yo); echo $?'
bash -c 'wait_and_tee () { sleep 1; tee "$@"; };
echo hi | wait_and_tee >(echo yo); echo $?'
最初の亜種では何が起こったのか注意していますか?
$ bash -c 'echo hi | tee >(sleep 1; echo yo); echo $?'
hi
0
$ yo
プロセス置換コマンドはsleep 1; echo yo
外部コマンドと並列に実行され、bashは完了するまで待機しません。したがって、イベントの順序は次のようになります。
echo hi
,sleep 1; echo yo
3 つのコマンドがtee
並列に開始されます。echo hi
hi
出力を作成します(|
パイプライン)。tee
>(…)
で作成された他のパイプから標準出力とコマンドライン引数を読み書きします。これにより、1 つのコピーがhi
端末に印刷され、1 つのコピーが>(…)
パイプのバッファに保存されます。- 前の点と平行に
echo hi
終了してパイプの書き込み端を閉じます|
。 tee
入力ファイルの終わりに達したことがわかります。すべてのデータを記録したので終了します。- Bashの観点からは、パイプの両方が終了したので、コマンドは終了しました。 0が返されるので、
tee
パイプの状態は0です。 - 1秒後に
sleep 1
終了してecho yo
実行されます。
2番目のバリエーションでは、始める前に強制終了し、前を強制終了しますecho yo
。今回はイベントの順番は次のとおりです。tee
tee
echo hi
,echo yo
3 つのコマンドがsleep 1
並列に開始されます。echo hi
hi
出力を作成します(|
パイプライン)。- 前の箇条書きと平行に
echo yo
印刷yo
して終了します。 - しばらくして
sleep 1
終了してtee
起動します。 tee
入力から読み込み、hi
それを端末(標準出力)と引数として渡され>(…)
たパイプに書き込もうとします。読み取りのためにこのパイプを開いたプロセス(echo yo
)が1秒前に終了したため、パイプへの書き込み試行は失敗します。信号パイプライン(信号13、ここでシェルは 128+signal_number を報告します。)。
G-Manが説明するように、hi
2番目の場合に表示されるかどうかは、tee
標準出力またはファイル引数に最初に書き込もうとするかどうかによって異なります。
呼び出しがなければ、sleep
タイミングはどちらの方向にも進むことができます(Linuxでは約半分/半分を取得します。他のカーネルはあるタイミングを他のものよりも可能にすることができます)。