Command-Line

Linux 實用程序在執行管道命令時是否智能?

  • July 12, 2012

我只是在終端中執行了一些命令,我​​開始想知道,Unix/Linux 在執行管道命令時會走捷徑嗎?

例如,假設我有一個包含一百萬行的文件,其中前 10 行包含hello world. 如果您執行該命令grep "hello world" file | head,第一個命令會在找到 10 行後立即停止,還是繼續先搜尋整個文件?

有點。shell 不知道你正在執行的命令會做什麼,它只是將一個的輸出連接到另一個的輸入。

如果grep發現超過 10 行寫著“hello world”,那麼head將擁有它想要的所有 10 行,然後關閉管道。這將導致grep被 SIGPIPE 殺死,因此它不需要繼續掃描非常大的文件。

當程序嘗試寫入管道並且沒有程序從該管道讀取時,寫入程序會收到SIGPIPE信號。程序收到 SIGPIPE 時的預設操作是終止程序。程序可以選擇忽略 SIGPIPE 信號,在這種情況下寫入會返回錯誤 ( EPIPE)。

在您的範例中,這是發生的時間線:

  • 和命令grep並行head啟動。
  • grep讀取一些輸入,開始處理它。
  • 在某些時候,grep產生第一塊輸出。
  • head讀取第一個塊並將其寫出。
  • 假設前 10 次匹配後有足夠的行數(否則grep可能首先終止),最終head將列印出所需的行數。此時,head退出。
  • 根據grephead程序的相對速度,grep可能已經積累了一些數據並且還沒有列印出來。在head退出時,grep可能正在讀取輸入或進行內部處理,在這種情況下它將繼續這樣做。
  • 很快grep就會寫出它處理的數據。那時,它會收到一個 SIGPIPE 並死掉。

它可能grep會處理比嚴格必要的輸入更多的輸入,但通常只有幾千字節:

  • head通常讀取幾千字節的塊(因為這比為每個字節發出read系統呼叫更有效 - 這種行為稱為緩衝),因此在所需的最後一行之後的最後一個塊的剩餘部分被丟棄。
  • 可能有一些數據在傳輸中,因為管道有一個由核心管理的關聯緩衝區(通常為 512 字節)。該數據將被丟棄。
  • grep可能已經積累了一些準備成為輸出塊的數據(再次緩衝)。當它試圖刷新它的輸出緩衝區時,它會收到 SIGPIPE。

總而言之,該系統經過精確設計,過濾實用程序自然而然地高效執行。當輸出通道消失時需要繼續執行的程序必須採取忽略 SIGPIPE 信號的步驟。

引用自:https://unix.stackexchange.com/questions/29964