Bash

為什麼是tac文件|grep foo'(管道)比 grep foo < <(tac file)’(程序替換)更快?

  • April 9, 2020

這個問題的動機是“反向 grepping ”,關於從下到上 grepping 一個巨大的文件。

@chaos 說

tac file | grep whatever

或者更有效一點:

grep whatever &lt; &lt;(tac file)

@vinc17 說

應該&lt; &lt;(tac filename)像管道一樣快

其他使用者也有許多有趣的評論。

我的問題:

  • |和 和有什麼不一樣&lt; &lt;()
  • 為什麼一個比另一個快?
  • 哪個真的更快?
  • 為什麼沒有人建議xargs

構造&lt;(tac file)導致殼:

  • 創建一個有名字的管道

    • 在 Linux 和 SysV 等具有的系統上/dev/fd,使用正常管道,並/dev/fd/&lt;the-file-descriptor-of-the-pipe&gt;用作名稱。
    • 在其他系統上,使用命名管道,這需要在磁碟上創建一個實際的文件條目。
  • 啟動命令tac file並將其連接到管道的一端。

  • 將命令行中的整個構造替換為管道的名稱。

替換後,命令行變為:

grep whatever &lt; /tmp/whatever-name-the-shell-used-for-the-named-pipe

然後grep執行,它讀取它的標準輸入(即管道),讀取它,並在其中搜尋它的第一個參數。

所以最終結果與…相同

tac file | grep whatever

…因為啟動了相同的兩個程序,並且仍然使用管道連接它們。但是&lt;( ... )構造更加複雜,因為它涉及更多步驟並且可能涉及臨時文件(命名管道)。

該構造是一個擴展,在標準 POSIX bourne shell 和不支持或命名管道&lt;( ... )的平台上均不可用。/dev/fd僅出於這個原因,因為所考慮的兩個替代方案在功能上完全相同,所以更便攜的command | other-command形式是更好的選擇。

由於&lt;( ... )額外的捲積,構造應該會更慢,但這只是在啟動階段,我不希望這種差異很容易測量。

注意:在 Linux SysV 平台上,&lt; ( ... )不使用命名管道,而是使用正常管道。正常管道(實際上是所有文件描述符)可以通過特殊命名來引用,/dev/fd/&lt;file-descriptor-number因此 shell 將其用作管道的名稱。通過這種方式,它避免了在真實文件系統中創建具有真實臨時文件名的真實命名管道。雖然/dev/fd訣竅是在最初出現時用於實現此功能ksh,但它是一種優化:在不支持此功能的平台上,如上所述使用真實文件系統中的正常命名管道。

另請注意:將語法描述為&lt;&lt;( ... )具有誤導性。實際上它是&lt;( ... ),它被替換為管道的名稱,然後作為&lt;整個事物前綴的另一個字元與此語法分開,它是用於從文件重定向輸入的正常眾所周知的語法。

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