比較 awk 與 grep

比較 awk 與 grep

我已經針對非常大的文件運行了以下兩個命令

grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4

awk '/string1|string2/ && /string3/ && /string4/' 151103*.log

執行時間幾乎相同。但awk更快地向我展示了匹配的結果。grep也向我展示了相同的結果,但最後,當過程完成時。

兩個過程都花了相同的時間來完成,只是想知道搜尋awk和背後的邏輯grep

為什麼awk更快?這兩個程式有不同的搜尋邏輯嗎?如果我在上面的搜尋中混淆了字串怎麼辦,這會對搜尋速度產生影響嗎?

答案1

GNUgrep緩衝輸出,但 GNUawk不緩衝。即使您沒有使用 GNUawk並且正在使用其他一些變體,如果您列印到終端,它可能仍然是行緩衝的,因此會刷新每個出現的\newline 的輸出,但您grep寫入管道,因此會阻塞 -無論如何緩衝。如果您有 GNU,grep您可以使用grep --line-buffered ... | grep ...它進行比較以盡快看到結果。可能grep會在幾乎任何比賽測試中擊敗awk——尤其是 GNU grep

sed也是做你想做的事:

sed -ne'/string4/{/string3/s/string[12]/&/p;}' <in >out

答案2

grep 管道在 string4 的最後一個匹配某些內容之前無法輸出任何內容grep,並且只有在前一個管道緩衝區填滿後才獲取輸入。查看相關問題管道緩衝區有多大?關閉管道中的緩衝

根據輸入中字串的頻率,透過將靜態搜尋放在第一位,您可以看到運行時的差異,從而減少擴展正則表達式的查看次數。

答案3

您的 awk 範例一次完成整個正規表示式搜尋。對於每一行輸入,如果找到第一、第二和第三個正規表示式,則會列印該行,並且您將立即看到輸出(在處理匹配行時)。

您的grep 範例使用3 個不同的grep 呼叫(每個正規表示式一個)來執行相同的操作,但每個呼叫的輸出都將成為下一個呼叫的輸入,這表示每個呼叫都需要在下一個呼叫需要處理之前完成。

如果您有一個 1000 行文件,並且只有第 5 行與所有三個正規表示式匹配,則 awk 命令將在處理第 5 行之後、處理第 6 行之前為您提供輸出。將其與管道 grep 語句進行比較。 grep 的第一次呼叫將找到第5 行以及可能與第一個正規表示式相符的任何其他行,並且在處理輸入的第1000 行(最後)行後,其輸出將成為grep 的第二次調用的輸入。 grep 的第二次呼叫會處理第一個輸出的許多行,並輸出與第一個和第二個正規表示式相符的行,然後這些行將成為 grep 第三次呼叫的輸入。當第三次呼叫 grep 處理每一行時,它將輸出與其正規表示式相符的任何行。

您可以比較上面範例中grep 的最佳和最差情況:如果除了第5 行(匹配所有5 行)之外,沒有任何行與任何正規表示式匹配,則第一個grep 處理1000 行,第二個grep 處理1 行,並且第三個 grep 處理 1 行:它將在產生任何輸出之前處理 1002 行(最好情況)。如果所有行都與前兩個正規表示式匹配,但只有一行與第三個正規表示式匹配,則管道grep 構造將處理1000 + 1000 行+ 5 = 2005 行,然後才能找到第5 行的匹配項並產生一些輸出(它將繼續處理第二個 grep 輸出中剩餘的 995 行,但您不會看到更多輸出,因為沒有其他內容匹配)。

將其與 awk 命令進行比較,該命令同時檢查每行的所有三個正則表達式,並在處理第 5 行後給出輸出。當您同時檢查更多文件時,差異會更大。

例如,比較一下如果不像上面那樣同時在所有文件上運行grep 命令,您是否會看到更快的輸出(理論上,您應該這樣做,但結果可能會根據整個文件中的命中分佈而有所不同):

grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4

您可以單獨對每個檔案執行一系列 grep 命令,如下所示:

for i in 151103*.log; 
  do grep -E 'string1|string2' $i |grep 'string3' | grep string4; 
done

這仍然不會像 awk 語句那樣快速產生輸出,但您可能會看到差異。

答案4

雖然 grep 、 awk 和 sed 可用於類似的任務,但每個都有其優點和缺點。

Awk 最適合表格資料或需要執行計算等時。

Sed 擅長替換文字。

Grep 最好從輸入資料中選擇行,因此我希望它比 awk 更快地完成此任務。也許如果您將 3 個 grep 命令合併為一個,您就會看到這樣的結果。現在 grep 處於劣勢,因為它需要啟動 3 次,第二次和第三次需要等待第一次的輸入。這也許可以解釋為什麼結果會延遲。雖然我對此並不確定。

相關內容