データがパイプラインでどのように流れるか理解していないので、誰かがそこで何が起こっているのかを明確にしてくれることを願っています。
コマンドのパイプラインがファイル(テキスト、文字列の配列)を1行ずつ処理すると思いました。 (各コマンド自体が1行ずつ機能する場合)。テキストの各行がパイプラインを通過すると、コマンドは前の行が入力全体の処理を完了するのを待ちません。
しかし、そうではないようです。
これがテストの例です。いくつかのテキスト行があります。それらを大文字にして、各行を2回繰り返します。 cat text | tr '[:lower:]' '[:upper:]' | sed 'p'
。
プロセスをたどるために、それを「インタラクティブに」実行できます-cat
の入力ファイル名をスキップします。パイプラインの各部分は1行ずつ実行されます。
$ cat | tr '[:lower:]' '[:upper:]'
alkjsd
ALKJSD
sdkj
SDKJ
$ cat | sed 'p'
line1
line1
line1
line 2
line 2
line 2
しかし、完全なパイプラインは、EOF
で入力が完了するのを待ってから、結果を出力します。
$ cat | tr '[:lower:]' '[:upper:]' | sed 'p'
I am writing...
keep writing...
now ctrl-D
I AM WRITING...
I AM WRITING...
KEEP WRITING...
KEEP WRITING...
NOW CTRL-D
NOW CTRL-D
そうなのでしょうか?なぜ行ごとではないのですか?
一般的なバッファリングルールに続いて、ほとんどのUNIXプログラムが使用するC標準I/Oライブラリ(stdio
)があります。出力が端末に送られる場合、各行の終わりでフラッシュされます。それ以外の場合は、バッファー(私のLinux/AMD64システムでは8K、ご使用のシステムでは異なる可能性があります)がいっぱいになったときにのみフラッシュされます。
すべてのユーティリティが一般的なルールに従っている場合、すべての例(cat|sed
、cat|tr
、およびcat|tr|sed
)で出力が遅延するのがわかります。ただし、例外があります:GNU cat
は出力をバッファリングしません。stdio
を使用しないか、デフォルトのstdio
バッファリングを変更しますポリシー。
他のUNIXはこのように動作しないため、GNU cat
ではなく他のunix cat
を使用していると確信できます。従来のunix cat
には、バッファリングされていない出力を要求する-u
オプションがあります。GNU cat
は、出力が常にバッファリングされないため、-u
オプションを無視します。
したがって、左側にcat
があるパイプがある場合、GNUシステムでは、パイプを介したデータの通過は遅延されません。cat
は1行ずつも実行されません-ターミナルはそれを行っています。猫の入力を入力している間、ターミナルは「標準」モードです-行ベースで、バックスペースやctrl-Uなどの編集キーを使用して、入力した行を編集してから送信する機会 Enter。
cat|tr|sed
の例では、tr
はcat
からデータをまだ受信しています。 Enter、ただしtr
はstdio
デフォルトポリシーに従っています。出力はパイプに送られるため、各行の後にフラッシュされません。バッファーがいっぱいになったとき、またはEOFを受け取ったときのどちらか早い方のタイミングで、2番目のパイプに書き込みます。
sed
もstdio
のデフォルトポリシーに従っていますが、その出力はターミナルに送られるため、各行が終了するとすぐに各行に書き込まれます。これは、何かがパイプラインのもう一方の端に表示される前に入力する必要がある量に影響します。sed
がその出力をブロックバッファリングしている場合は、2倍入力する必要があります(tr
の出力バッファandsed
の出力バッファ)。
GNU sed
には-u
オプションがあるため、順序を逆にしてcat|sed -u|tr
を使用すると、出力がすぐに再び表示されます。 (sed -u
オプションは他の場所で利用できるかもしれませんが、cat -u
のような古代のUNIXの伝統ではないと思います)私が知る限り、tr
に相当するオプションはありません。
stdbuf
と呼ばれるユーティリティがあり、stdio
のデフォルトを使用するコマンドのバッファリングモードを変更できます。 LD_PRELOAD
を使用してCライブラリがサポートするように設計されていない機能を実行するため、少し脆弱ですが、この場合は機能するようです。
cat | stdbuf -o 0 tr '[:lower:]' '[:upper:]' | sed 'p'
これは実際に私は理解するためにいくつかの考えを、そしてさらに答える必要がありました。すばらしい質問です(次に投票します)。
tr | sed
上記のデバッグ項目:
>tr '[:lower:]' '[:upper:]' | sed 'p'
i am writing
still writing
now ctrl-d
I AM WRITING
I AM WRITING
STILL WRITING
STILL WRITING
NOW CTRL-D
NOW CTRL-D
>
したがって、明らかにtr
バッファです。毎日新しいことを学びましょう!
[〜#〜]編集[〜#〜]:
私はこれを考えすぎたので、原因を特定しましたが、説明はしていません。もし、あんたが cat | tr
、あなたがcat | sed
、すぐに書きますが、tr | sed
、EOF
を待ちます。その場合、答えはtr
またはsed
ソースコードに埋め込まれる可能性があり、パイプの問題ではない可能性があります。
[〜#〜]編集[〜#〜]:
最後の編集を入力しているときにWumpusが説明を提供しているのがわかります。ありがとう!