關于Shell腳本效率優化的一些個人想法
2019-10-26 18:31:57
供稿:網友
一、先說一下Shell腳本語言自身的局限性
作為解釋型的腳本語言,天生就有效率上邊的缺陷。盡管它調用的其他命令可能效率上是不錯的。
Shell腳本程序的執行是順序執行,而非并行執行的。這很大程度上浪費了可能能利用上的系統資源。
Shell每執行一個命令就創建一個新的進程,如果腳本編寫者沒有這方面意識,編寫腳本不當的話,是非常浪費系統資源的。
二、我們在Shell腳本語言的局限性上盡可能的通過我們有經驗的編碼來提高腳本的效率。
1、比如我想做一個循環處理數據,可能是簡單的處理一下數據,這樣會讓人比較容易就想到Shell里的循環類似這樣:
代碼如下:
sum=0
for((i=0;i<100000;i++))
do
sum=$(($sum+$i))
done
echo $sum
我們可以使用time這個腳本來測試一下十萬次循環的三次執行耗時:
real 0m2.115s
user 0m1.975s
sys 0m0.138s
real 0m2.493s
user 0m2.173s
sys 0m0.254s
real 0m2.085s
user 0m1.886s
sys 0m0.195s
平均耗時2.2s,如果你知道awk命令里的循環的話,那更好了,我們來測試一下同數據規模的循環三次執行耗時:
代碼如下:
awk 'BEGIN{
sum=0;
for(i=0;i<100000;i++)
sum=sum+i;
print sum;
}'
real 0m0.023s
user 0m0.018s
sys 0m0.005s
real 0m0.020s
user 0m0.018s
sys 0m0.002s
real 0m0.021s
user 0m0.019s
sys 0m0.003s
你都不敢想象平均時間僅0.022s,基本上純循環的效率已經比Shell高出兩位數量級了。事實上你再跑百萬次的循環你會發現Shell已經比較吃力了,千萬級的更是艱難。所以你應該注意你的程序盡量使用awk來做循環操作。
2、關于正則,經常寫Shell的同學都明白它的重要性,但是你真的能高效使用它嗎?
下邊舉個例子:現在我有一個1694617行的日志文件 action.log,它的內容類似:
2012_02_07 00:00:04 1977575701 183.10.69.47 login 500004 1977575701 old /***/port/***.php?…
我現在想獲取//之間的port的字符串,我可以這樣:
awk -F'/' ‘{print $3}' < 7action.log > /dev/null
但是你不會想知道它的效率:
real 0m12.296s
user 0m12.033s
sys 0m0.262s
相信我,我不會再想看著光標閃12秒的。但是如果這樣執行:
awk ‘{print $9}' < 7action.log | awk -F'/' '{print $3}' > /dev/null
這句的效率三次分別是:
real 0m3.691s
user 0m5.219s
sys 0m0.630s
real 0m3.660s
user 0m5.169s
sys 0m0.618s
real 0m3.660s
user 0m5.150s
sys 0m0.612s
平均時間大概3.6秒,這前后效率大概有4倍的差距,雖然不像上一個有百倍的差距,但是也足夠讓4小時變成1小時了。我想你懂這個差距的。
其實這個正則實例你可以嘗試推測其他的情況,因為正則每次運行都是需要啟動字符串匹配的,而且默認的分隔符會較快的按字段區分出。所以我們在知道一些數據規律之后可以嘗試大幅度的縮短我們將要進行復雜正則匹配的字符串,這樣會根據你縮減數據規模有一個非常明顯的效率提升,上邊還是驗證的比較簡單的正則匹配情況,只有一個單字符“/”,你可以試想如果正則表達式是這樣: