管道,數據如何在管道中流動?
我不明白數據如何在管道中流動,希望有人能澄清那裡發生了什麼。
我認為命令管道以逐行方式處理文件(文本、字元串數組)。(如果每個命令本身逐行執行。)每一行文本都通過管道,命令不會等待前一個完成整個輸入的處理。
但似乎並非如此。
這是一個測試範例。有幾行文字。我將它們大寫並重複每行兩次。我這樣做了
cat text | tr '[:lower:]' '[:upper:]' | sed 'p'
。為了遵循這個過程,我們可以“互動地”執行它——跳過
cat
. 管道的每個部分逐行執行:$ 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
應該是這樣嗎?為什麼不是逐行顯示?
stdio
大多數 unix 程序使用的 C 標準 I/O 庫 ( ) 遵循一般緩衝規則。如果輸出到終端,則在每行末尾刷新;否則,僅當緩衝區(我的 Linux/amd64 系統上為 8K;在您的系統上可能不同)已滿時才會刷新它。如果您的所有實用程序都遵循一般規則,您將在所有範例中看到輸出延遲(
cat|sed
、cat|tr
和cat|tr|sed
)。但是有一個例外:GNUcat
從不緩衝它的輸出。它要麼不使用,要麼stdio
更改了預設stdio
緩衝策略。我可以相當肯定你使用的是 GNU
cat
而不是其他的 unixcat
,因為其他的 unix 不會這樣。傳統的 unixcat
有一個-u
請求無緩衝輸出的選項。GNUcat
忽略該-u
選項,因為它的輸出總是無緩衝的。所以只要你有一個
cat
左邊有a的管道,在GNU系統中,通過管道的數據傳輸不會被延遲。cat
甚至沒有逐行進行-您的終端正在這樣做。當您為 cat 輸入輸入時,您的終端處於“規範”模式 - 基於行,使用退格鍵和 ctrl-U 等編輯鍵讓您有機會在發送之前編輯您輸入的行Enter
。在
cat|tr|sed
範例中,只要您按下,tr
它仍然會從那裡接收數據,但遵循預設策略:它的輸出將發送到管道,因此它不會在每行之後刷新。當緩衝區已滿或收到 EOF 時,它會寫入第二個管道,以先到者為準。cat``Enter``tr``stdio
sed
也遵循stdio
預設策略,但它的輸出將發送到終端,因此它會在完成後立即寫入每一行。這會影響在管道的另一端出現某些內容之前您必須輸入多少 - 如果sed
正在對其輸出進行塊緩衝,則您必須輸入兩倍的內容(以填充tr
’ 的輸出緩衝區和sed
’ 的輸出緩衝)。GNU
sed
有-u
選項,因此如果您顛倒順序並使用cat|sed -u|tr
,您會看到輸出立即再次出現。(該選項可能在其他地方可用sed -u
,但我認為它不像.cat -u``tr
有一個名為的實用程序
stdbuf
可以讓您更改使用stdio
預設值的任何命令的緩沖模式。它有點脆弱,因為它用於LD_PRELOAD
完成 C 庫並非旨在支持的事情,但在這種情況下,它似乎可以工作:cat | stdbuf -o 0 tr '[:lower:]' '[:upper:]' | sed 'p'