昨天一個同事遇到一個需求: 有一個日志文件A,當(dāng)日志文件中的某行包含某個字符串BC時,將字符串EF變成EG,并輸出到新文件。即: Input,A: asdfasdf asdfasdBCasdfEFasd
output: asdfasdf asdfasdBCasdfEGasd
這個文件有500w+行。 最開始用如下腳本解決:
cat $1 | while read line do echo $line | grep -q "BC" if [ $? -eq 0 ] ; then echo $line | sed "s/EF/EG/g" >> $1.out else echo $line >>$1.out fi done
上述腳本在循環(huán)中使用了grep、sed等外部命令,由于外部命令要fork一個process,因此效率極為低下。初步估計,運(yùn)行完要25個小時以上。因此將循環(huán)中的grep和sed替換掉,見如下:
cat $1 | while read line do [[ "$line" == *"BC"* ]] && echo ${line/EF/EG} || echo ${line} done
循環(huán)內(nèi)部的代碼簡潔了很多,而且吧grep、sed等external command替換掉,在循環(huán)內(nèi)部不會再有process 被fork出來。雖然執(zhí)行效率提高很多,但也沒有在我的耐心區(qū)間內(nèi)得到結(jié)果,初步估算執(zhí)行完需要半個小時以上。 問題應(yīng)該不在循環(huán)內(nèi)部,而是這種cat+while+read遍歷文件內(nèi)容的方式有問題。
換了awk的方式來做:
#!/bin/awk -f { if(match($0,"BC")){ print gsub("EF","EG"); } else{ print $0; } } 這次效率有很大的提升,耗時18秒就出來了結(jié)果。 按理說這已經(jīng)比較滿足需求了。
不過,我的同事又試了另外一種方法,用perl解決問題: –這段代碼是我一個同事寫的。
#!/usr/bin/perl open URLFILE, ">>aa"; my $cnt=0; while (<>) { if (/BC/) { s/EF/EG/g; } print URLFILE $_; }
這段代碼的執(zhí)行效率很高,比awk效果還要好,13秒。 按理說,就讀取文件的效率來說,perl雖然很快但應(yīng)該不會比awk快。
只是這個Perl中所做的工作只是讀取文件的一行,而awk在讀取完一行后,還要按照分隔符將$0劃分成一個個字段,分別存在$1,,,$n中,只是,我們這個需求并沒有用到這個功能,用awk解決這個需求還是有點(diǎn)大材小用了。
關(guān)于在shell下用什么方法來完成對文件的高效遍歷,還有什么更好的方法嗎?
|
|