データがパイプラインを通ってどのように流れているのか理解できず、誰かがそこで何が起こっているのかを明確にできることを願っています。
コマンドパイプラインは、ファイル(テキスト、文字列の配列)を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
そうすべきですか?なぜ一行ずつ?
答え1
stdio
ほとんどのUNIXプログラムで使用されるC標準I / Oライブラリ()は、共通のバッファリング規則に従います。出力が端末に移動すると、各行の末尾でフラッシュされます。それ以外の場合は、バッファ(Linux / amd64システムでは8K、ユーザーシステムでは異なる場合があります)がいっぱいの場合にのみフラッシュされます。
すべてのユーティリティの一般的な規則に従って、すべての例(、および)でcat|sed
出力cat|tr
遅延を確認できますcat|tr|sed
。 1つの例外があります。 GNU はcat
出力をバッファリングしません。未使用またはデフォルトのstdio
バッファstdio
リングポリシーが変更されます。
cat
私はあなたが他のUnixではなくGNUを使用していると確信しています。cat
なぜなら他のUNIXではこれをしないからです。従来のUnixには、バッファリングされていない出力を要求するオプションがcat
あります。-u
GNUは、出力が常にバッファリングされていないため、cat
このオプションを無視します。-u
cat
したがって、左側にパイプがある限り、パイプを介したデータ転送はGNUシステムで遅延されません。一行ずつ実行するのではなく、cat
端末で行う作業です。 catへの入力を入力すると、端末はバックスペースやCtrl-Uなどの編集キーを使用して「標準」モードの行ベースに設定され、sendを使用する前に入力した行を編集する機会を提供しますEnter。
例では、cat|tr|sed
を押すたびにデータは引き続き受信されますが、デフォルトのポリシーにtr
従います。その出力はパイプに送られるので、各行の後にフラッシュされません。バッファがいっぱいになったり、EOFが受信された場合(最初に発生した場合)、2番目のパイプに書き込みます。cat
Entertr
stdio
sed
また、stdio
デフォルトのポリシーに従いますが、出力は端末に送信されるため、完了するとすぐに各行が書き込まれます。これは、パイプの反対側に何かが表示される前に入力する必要がある量に影響します。出力がブロックバッファリングされている場合は、出力バッファを埋めるsed
ために2倍の入力が必要です。tr
そして sed
出力バッファ)。
GNUにはオプションがsed
あるので、-u
順序を変更して使用するとcat|sed -u|tr
すぐに出力が再び表示されることがわかります。 (このsed -u
オプションは他の場所でも使用できますが、そのような古いUnixの伝統ではないようですcat -u
。)私が知っている限り、それに対応するオプションはありませんtr
。
stdbuf
デフォルト値を使用するすべてのコマンドに対してバッファリングモードを変更できるユーティリティがありますstdio
。LD_PRELOAD
Cライブラリはサポートされていない操作を実行するために使用されるため、少し脆弱ですが、この場合は機能しているようです。
cat | stdbuf -o 0 tr '[:lower:]' '[:upper:]' | sed 'p'
答え2
実際に理解するには少し考えが必要で、答えにはもっと時間がかかりました。良い質問です(次に投票します)。
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
編集する:
アップを見ました。説明を提供最後の編集内容を入力しています。ありがとうございます!