shell 中遍历文件的效果比较
假设我们有一个数据文件形如下:
A,B
A,C
A,D
B,E
B,F
D,A
D,B
E,G
....
?
需求是要将其转变为如下形式:
A:B,C,D
B:E,F
D:A,B
E,G
......
?
?
需求很简单,循环遍历文件,然后trace第一列即可。
在这里,我们讨论用Shell脚本如何实现这个简单的需求。
?
?
在shell中面对这样的需求,最好的办法莫过于使用awk了,不过除了awk之外,linux也有其他命令能遍历文件内容,比如说cat以及输入重定向等,下面我们就对这几种文件遍历方法做下比较。
?
首先申明一点,关于文件遍历过程中,如果得到目标结果的逻辑是一样的,说白了就是每读入一行,检查第一列而已。
?
1. awk方法:
?
BEGIN{ FS="," curmember="";}{ if(curmember==""){ curmember=$1; offer=$2; } else if(curmember != $1){ print curmember":"offer curmember=$1; offer=$2; } else{ offer=offer","$2; }}END{ print curmember":"offer;}??
2. forIn+cat方法:
?
#!/bin/bashcurmember="";offer="";#cat orderinfo | while read linefor line in `cat orderinfo`do tmpmember=${line%%,*}; if [ "$curmember" == "" ]; then curmember=$tmpmember offer=${line##*,} elif [ "$tmpmember" != "$curmember" ]; then echo ${curmember}:${offer} curmember=${tmpmember} offer=${line##*,} else offer=${offer},${line##*,} fidoneecho ${curmember}:${offer}??
3. 文件描述符打开文件
?
#!/bin/bashcurmember="";offer="";exec 4<orderinfowhile read line<&4do tmpmember=${line%%,*}; if [ "$curmember" == "" ]; then curmember=$tmpmember offer=${line##*,} elif [ "$tmpmember" != "$curmember" ]; then echo ${curmember}:${offer} curmember=${tmpmember} offer=${line##*,} else offer=${offer},${line##*,} fidoneexec 4<&-echo ${curmember}:${offer}?
?
4. while循环中直接输入重定向
?
#!/bin/bashcurmember="";offer="";while read linedo tmpmember=${line%%,*}; if [ "$curmember" == "" ]; then curmember=$tmpmember offer=${line##*,} elif [ "$tmpmember" != "$curmember" ]; then echo ${curmember}:${offer} curmember=${tmpmember} offer=${line##*,} else offer=${offer},${line##*,} fidone<orderinfoecho ${curmember}:${offer}??
四种方法的执行效率如下,文件行数69000+
?
awk ? : 185 ms
forIn : 7187 ms
exec ?: 7931 ms
while : 7708 ms
?
上述结果中awk速度是最快的,其他三个虽然各有快慢,但都差不多,而且都比awk要慢很多。
?
这也印证了awk在流式处理文件中的先天优势,同时其代码也是最简单的,屏蔽了文件操作的相关内容。