我已經針對非常大的文件運行了以下兩個命令
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
並且正在使用其他一些變體,如果您列印到終端,它可能仍然是行緩衝的,因此會刷新每個出現的\n
ewline 的輸出,但您grep
寫入管道,因此會阻塞 -無論如何緩衝。如果您有 GNU,grep
您可以使用grep --line-buffered ... | grep ...
它進行比較以盡快看到結果。可能grep
會在幾乎任何比賽測試中擊敗awk
——尤其是 GNU grep
。
這sed
也是做你想做的事:
sed -ne'/string4/{/string3/s/string[12]/&/p;}' <in >out
答案2
答案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 次,第二次和第三次需要等待第一次的輸入。這也許可以解釋為什麼結果會延遲。雖然我對此並不確定。