关于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小时了。我想你懂这个差距的。
其实这个正则实例你可以尝试推测其他的情况,因为正则每次运行都是需要启动字符串匹配的,而且默认的分隔符会较快的按字段区分出。所以我们在知道一些数据规律之后可以尝试大幅度的缩短我们将要进行复杂正则匹配的字符串,这样会根据你缩减数据规模有一个非常明显的效率提升,上边还是验证的比较简单的正则匹配情况,只有一个单字符“/”,你可以试想如果正则表达式是这样: