Home » Code » awk基础使用之分组计算

awk基础使用之分组计算

对大体积的日志文件进行数据统计,可以使用awk。

有的日志文件可能数据较多较杂,首先需要筛选,可以直接使得grep进行重定位输出。如:

grep "Newusershare::run" newusershare.log >> /tmp/newusershare.log

得到的文本不是很大,110M,但也不小了。格式如下:

20161223100001 App\Model\Cron\Newusershare::run success send!, uid: 30137326, day: 1, bbtype: null, tid: 17216223 
20161223100001 App\Model\Cron\Newusershare::run success send!, uid: 30137328, day: 1, bbtype: null, tid: 17216223 
20161223100002 App\Model\Cron\Newusershare::run success send!, uid: 30137330, day: 1, bbtype: null, tid: 17216223 
20161223100002 App\Model\Cron\Newusershare::run success send!, uid: 30137333, day: 1, bbtype: null, tid: 17216223 
20161223100002 App\Model\Cron\Newusershare::run success send!, uid: 30137334, day: 1, bbtype: null, tid: 17216223 
20161223100002 App\Model\Cron\Newusershare::run success send!, uid: 30137335, day: 1, bbtype: null, tid: 17216223 
20161223100002 App\Model\Cron\Newusershare::run success send!, uid: 30137336, day: 1, bbtype: null, tid: 17216223 
20161223100002 App\Model\Cron\Newusershare::run success send!, uid: 30137337, day: 1, bbtype: null, tid: 17216223 
20161223100002 App\Model\Cron\Newusershare::run success send!, uid: 30137338, day: 1, bbtype: null, tid: 17216223 
20161223100003 App\Model\Cron\Newusershare::run success send!, uid: 30137339, day: 1, bbtype: null, tid: 17216223

这是一个发送日志,如果要统计每天不同day值的数量(也就是按天和day值分组),如何做呢?使用awk能比较简单的实现:

awk -v OFS="," -F " " '{x[substr($1, 0, 8)","substr($8, 0, 1)]+=1} END{for( i in x ){print i,x[i]}}' /tmp/newusershare.log |more
20161231,1,10974
20161231,2,14042
20161231,3,12437
20161231,4,19082
20161231,5,9862
20161231,6,9076
20161231,7,6892
20170102,1,6190
20170102,2,5241
20170102,3,10915
20170102,4,14001
20170102,5,12414
20170102,6,19070
20170102,7,9856

对于上术命令,-v是设定一些参数,要设置多个参数用’;’割开。基本的以下四个参数是设定的:

  • FS,输入字段分割符,默认空格
  • RS,输入行行分割符,默认\n
  • OFS,输出字符分割符,默认空格
  • ORS,输出行分割符,默认\n

-F其实就是设置FS,上边显式的设置了一下,不设置默认就是空格,一样的结果。x[]类似循环为数组赎值,键是第1个字段的前8位边连上’,’再连上第8个字段的第一位,就是为了得到’20171231,1’,值是每一行就累加1。END命令结束后循环数组输出键和值,输出多个变量用’,’隔开,加上前边设置了输出分割符是’,’,就得到了最终结果如:20171231,1,10974。这格式的数据直接定向到一个文件,把后缀改为csv就可以用excel打开了。

以上是一个我直接应用的分组求和的例子。以下例子摘抄自网络。

数据:

[root@localhost wms]# cat groupandsum.txt 
John|P|physics|2|02/12/2002
Rick|L|Mechanical|1|02/12/2002
Jack|T|electrical|3|03/12/2003
Phil|R|Electrucal|1|03/12/2003
Mike|T|mechamical|2|10/12/2003
Paul|R|chemical|2|10/12/2003
John|T|chemical|3|10/12/2002
Tony|N|chemical|2|10/11/2003
James|R|Electrucal|2|10/11/2003

一般求和:

awk -F '|' '{sum1 += $4} END {print sum1}' groupandsum.txt

一般分组:

[root@localhost wms]# awk -F "|" '{x[$5]+=$4} END{for( i in x ){print i,x[i]}}' groupandsum.txt 
03/12/2003 4
02/12/2002 3
10/12/2002 3
10/12/2003 4
10/11/2003 4

二次分组:

[root@localhost wms]# awk -F "|" '{x[$5"-"$3]+=$4} END{for( i in x ){print i,x[i]}}' groupandsum.txt 
10/12/2002-chemical 3
03/12/2003-Electrucal 1
03/12/2003-electrical 3
02/12/2002-Mechanical 1
10/12/2003-mechamical 2
02/12/2002-physics 2
10/11/2003-Electrucal 2
10/11/2003-chemical 2
10/12/2003-chemical 2

格式化处理:

awk -F'|' '{a[$5]+=$4}END{for(i in a)printf("%s\t%d\n",i,a[i])}' groupandsum.txt

一般情况下求平均:

[root@localhost wms]# awk -F'|' '{sum+=$4} END {print "Average = ", sum/NR}' groupandsum.txt 
Average =  2

分组求平均:

[root@localhost wms]# awk -F'|' '{a[$5]+=$4;ca[$5]++}END{for(i in a)printf("%s\t%d\taverage:%d\n",i,a[i],a[i]/ca[i])}' groupandsum.txt
03/12/2003      4       average:2
02/12/2002      3       average:1
10/12/2002      3       average:3
10/12/2003      4       average:2
10/11/2003      4       average:2

注意了,/ 求是整数,% 求余数。/ 也能求得完整的值,只是没有显示而已,用%.2f就可以显示了。

[root@localhost wms]# awk -F'|' '{a[$5]+=$4;ca[$5]++}END{for(i in a)printf("%s\t%d\t%.2f\n",i,a[i],a[i]/ca[i])}' groupandsum.txt
03/12/2003      4       2.00
02/12/2002      3       1.50
10/12/2002      3       3.00
10/12/2003      4       2.00
10/11/2003      4       2.00

一般情况下求最大最小:

[root@localhost wms]# awk -F'|' 'BEGIN {max=0}{if($4>max){max=$4}} END{print max}' groupandsum.txt
3

分组求最大最小:

[root@localhost wms]# awk -F'|' '{if($4>x[$5]){x[$5]=$4}} END{for (i in x) print i,x[i] }' groupandsum.txt
03/12/2003 3
02/12/2002 2
10/12/2002 3
10/12/2003 2
10/11/2003 2

分组整理字符串:

a 111                                                                     
a 222                                                                                                  
a 333                                                                   
b 444                                                                   
d 555                                                                   
                                                                           
awk '{x[$1]=x[$1]"\n"$2} END{for( i in x ){print i":", x[i]}}' juhe.txt

a:                                                                         
111                                                                        
222                                                                        
333                                                                        
b:                                                                         
444                                                                        
555 

参考文章:
http://blog.itpub.net/25960404/viewspace-1818866/

2 comments

  1. 表示太复杂了的,,不懂这个

  2. 支持一下,虽然我不懂代码,呵呵

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Time limit is exhausted. Please reload CAPTCHA.