一个 Shell 程序的性能优化

编写 Linux Shell 脚本程序不要仅限于完成基本的程序功能,认真的分析 Shell 脚本并找出优化的方法对个人能力的提高以及对脚本程序的质量改善都有重要的意义,希望读者能从本文中获得许多实用的 Shell 程序方法。

本文 Shell 程序运行环境:

程序运行环境 Redhat Linux As3 GNU bash, version 2.05b.0(1)-release (i386-redhat-linux-gnu) 代码清单:shellcode.txt

问题描述:有一个普通的通话话单文件(包括"计费号码","主叫号码","被叫号码","开始时间","结束时间","时长","费用"等其它字段),要求根据另外一个号段配置文件(由"号段下限"和"号段上限"两个字段组成)将此话单文件进行分拣过虑。

分拣规则:如果通话话单文件中的"计费号码"位于号段文件的某个号段内,则将此条记录计入结果文件 1,否则计入结果文件 2。

通话话单文件样例:

 

9013320003|9013320003|9918128025|20060814163420|20060814163450|30|20|00|01|0059926645208|9926645208|9918188065|20060814163415|20060814163545|90|30|00|01|0059934877207|9934877207|9936972003|20060814163620|20060814163930|190|50|00|01|005............

 

号段配置文件样例:

 

9013305000,90133279999013767000,90137689999923670000,99236799999928998000,99289999999932310000,99323199999932333400,99323335999936034000,99360369999936084000,99360849999998537000,99985379999998620000,99986299999998690000,9998699999

 

例如:

对于通话话单文件的第一条记录中的"计费号码"为 9013320000,此号码正好属于号段配置文件的第一个号段 9013305000,9013327999中,即:条件 9013305000<= 9013320000 <=9013327999 成立,所以应该将通话话单文件的第一条记录计入结果文件 1 中;对于通话话单文件中的第二条记录的"计费号码"为 9926645208 它不属于号段文件中的任何一个段,所以应该将通话话单的第二条记录计入结果文件 2 中。

对于这样一个简单的问题首先想到的解决方法为:

解决方法1:

写一个双重循环,外层循环为逐条读取"通话话单文件"并获取每条记录的第一个字段的值"计费号码",内层循环:根据外层循环获得的"计费号码"在"号段文件"中循环比较,判断此号码是否属于相应号段。

程序代码如下(省略了文件存在性判断等语句):

 

while read fdoorg="$(expr substr ${f} 1 10)" #取得"计费号码"存入变量org中while read numsegdonglow="$(expr substr ${numseg} 1 10 )" #将号段下限存入变量nglowngtop="$(expr substr ${numseg} 12 10 )" #将号段上限存入变量ngtopif [ "$org" > "$nglow" -a "$org" < $ngtop ]#判断"计费号码"是否在此号段内thenecho "${f}" >> ./resultfile1.cdr #如果在此号段内,将此记录计入结果文件1中else echo "${f}" >> ./resultfile2.cdr #如果不在此号段内,将此记录计入结果文件2中fidone < ./numseg.txtdone < ./rttest.txt

 

解决方法1 对于号段文件和通话话单的记录数都比较少的情况下基本可以完成工作,但是当两个文件的记录数较多(例如号段文件>50条,话单文件> 10000条)的时候,这种方法就会花费几个小时甚至几天的时间才能得出处理结果。此脚本程序执行慢的原因是对第二个循环内的比较运算只用了最简单的顺序比较方法,所以当号段文件的记录增多的时候,脚本的执行速度会急剧下降。

解决方法2:

将内层循环的逐个比较的方法改为二分查找法进行判断,程序代码如下:

 

#!/bin/bash#Author Xsh date:08-15-2006#程序中使用了二分查找法进行号码的范围判断#为突出重点,省略了文件存在性判断和异常捕获以及帮助提示等程序语句#程序的工作目录为当前目录echo "Time:$(date)==>Strat to processing........." #显示程序开始运行时间while read numsegdotmplow="${tmplow} $(expr substr ${numseg} 1 10 & >/dev/null ) "tmptop="${tmptop} $(expr substr ${numseg} 12 10 & >/dev/null ) "done < ./numseg.txt#读取号段文件,下限号段存入变量tmplow,上限号段存入变量tmptoparr_lownug=(${tmplow}) #将下限号段存入数组arr_lownugarr_topnug=(${tmptop})#将上限号段存入数组arr_topnug#定义函数checknum(),输入参数为需要检查的"计费号码",输出参数为0或者1#若checknum()输出为0 表示"计费号码" 不在号段文件的所有号段范围内#若checknum()输出为1 表示"计费号码" 在号段文件的所有号段范围内# checknum()函数中用二分搜索法进行号码的判断checknum(){thisnum=$1ckresult=0lowflag=0topflag=$(expr ${#arr_lownug[*]} - 1 ) #标注1MaxIndex=$(expr ${#arr_topnug[*]} - 1 ) #标注2midflag=0midflag=$(expr ${topflag} / 2 )#标注3if [ "${thisnum}" < "${arr_lownug[0]}" -o "${thisnum}" >"${arr_topnug[${MaxIndex}]}" ]thenreturn 0elsewhile [ "$lowflag" != "$midflag" ]doif[ "$thisnum" > "${arr_lownug[${midflag}]}" -o "$thisnum" == "${arr_lownug[${midflag}]}" ]thenlowflag=${midflag}midflag=$(expr `expr ${topflag} + ${lowflag}` / 2 ) #标注4elif["$thisnum"<"${arr_lownug[${midflag}]}" -o "$thisnum" == "${arr_lownug[${midflag}]}" ] thentopflag=${midflag}midflag=$(expr `expr ${topflag} + ${lowflag}` / 2 ) #标注5elseecho "Error!" fidone if [ "$thisnum" < "${arr_topnug[${lowflag}]}" -o "$thisnum" == "${arr_topnug[${lowflag}]}" ]thenreturn 1else return 0 fifi}#函数定义完毕while read fdoorg="$(expr substr ${f} 1 10)" #标注6checknum ${org}returnval=$?if [ "$returnval" == "1" ]then echo "${f}" >> ./Match_result.cdr #将匹配的记录存入结果文件1elseecho "${f}" >> ./NoMatch_result.cdr #将不匹配的记录存入结果文件2fidone < ./rttest.txt echo "Time:$(date) ==> Proccess is end! "exit 0;


标签: 性能优化程序
上一页 1 2 下一页
------分隔线----------------------------
· 首页 · 注册

百鸣[Baiming.org]欢迎您 百鸣[Baiming.org]欢迎您~