Bash
如何提高 bash 腳本中的 cat 和 xargs 性能
我必須處理一個包含 100 萬個域行呼叫的文件:
1m.txt
現在我的腳本正在驗證 1m.txt 中包含的行:
cat out.txt > advance.txt 2> /dev/null cat 1m.txt | xargs -I {} -P 100 sh -c "if ! grep --quiet {} advance.txt; then if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi; fi" >> out.txt
這個腳本的作用是,如果它被中斷(ctrl + c)並重新啟動,它會從處理的最後一行開始。如果有 1000 行,在 200 行中斷程序時重啟很快。但是 100 萬行和 500k 行中斷程序需要幾個小時
有沒有辦法讓它更有效率?
所以你目前的邏輯是“對於1m.txt中的每一行,看看它是否已經是advanced.txt。如果沒有,則處理它並將其添加到out.txt。當工作開始時,用所有行更新advance.txt在 out.txt’ 中。
這樣做的問題是,隨著更多行添加到Advance.txt,每行必須比較的行越多。作為最壞的情況,如果每行都已處理,則需要檢查 1m.txt 中的每一百萬行中的每一行,以查看它是否是提前的.txt。平均而言,您需要在 Advance.txt 中比較一半的行,因此這將需要 1,000,000*500,000 或 500,000,000,000(5000 億)次比較。
如果您沒有並行處理事情,那麼直接的處理方法是找到 out.txt 中的最後一行,然後跳過 1m.txt 中的所有行直到該點。例如
# Pipe the output of the if/then/else/fi construct to xargs. # use the if/then/else/fi to select the input. # Use '-s' to see if the file exists and has non zero size. if [ -s out.txt ] ; then # we have some existing data # Get the host from the last line # delete anything that is not the last line # remove the DIE/OK. quote anything not alphabetic with a backslash. lasthost="$(sed '$!d;s/^\(DIE\|OK\) //;s/[^0-9a-zA-Z]/\\&/g' out.txt)" # get the lines from 1m.txt from after the matched host # uses GNU sed extension to start at line "0" sed "0,/^$lasthost\$/d" 1m.txt else # no existing data, so just copy the 1m.txt using cat cat 1m.txt fi | xargs -I {} sh -c "if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi" >> out.txt
但是,您正在並行處理事情。由於
host
返回值可能需要非常多變的時間,因此可以顯著重新排列輸入。需要一種更快的方法來查看主機是否已經被看到。標準方法是使用某種雜湊表。一種方法是使用awk
.if [ -s out.txt ] ; then # we have some existing data. Process the two files given # for the first file set the entries of the seen array to 1 # for the second file print out the hosts which have not been seen. awk 'FNR==NR {seen[$2]=1;next} seen[$1]!=1' out.txt 1m.txt else cat 1m.txt fi | xargs -I {} -P 100 sh -c "if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi" >> out.txt