awk命令之通过在awk中使用数组及for循环来统计不同IP出现的次数

- 脚本

最新没事通过阿里云手机app查看本站CDN使用状态,发现CDN统计信息中返回码4xx的占比一直持续很多,基本30%左右,有时候还飙到100%了快。通过查看nginx日志,发现有很多IP在刷站点上根本不存在的地址,所以有大量404出现。于是想统计下看哪些IP访问404页面比较多,将其加到黑名单,限制访问本站点。既然要统计不同IP出现次数了,肯定要用awk来比较方便了。记得之前有用awk来统计linux下不同状态连接数。但是真用起来突然发现不知道怎么用了。。。时间真是把杀猪刀⊙﹏⊙||| 又查了半天资料才给搞好,,于是想着还是记录下笔记吧!


示例文本

为了方便讲解,这里就不拿nginx日志来做演示了,只给出一个包含不同IP的文件(效果都是一样的,处理nginx日志只是提前将状态码404的行都筛选出来,然后再统计IP那一列出现次数而已,例如:awk '/\<404\>/{print $1}')。

[root@imzcy ~]# cat test.txt
192.168.1.3
192.168.1.3
192.168.1.2
192.168.1.6
192.168.1.2
192.168.1.3
192.168.1.6
192.168.1.3
192.168.1.6
192.168.1.2
192.168.1.2
192.168.1.2
192.168.1.2
192.168.1.2
192.168.1.2
192.168.1.2
192.168.1.6
192.168.1.6
192.168.1.6
192.168.1.6
[root@imzcy ~]#




统计出不同IP出现的次数

[root@imzcy ~]# cat test.txt |awk '{a[$1]+=1;} END {for(i in a){print a[i]" "i;}}'
9 192.168.1.2
4 192.168.1.3
7 192.168.1.6
[root@imzcy ~]#




执行过程解释

上面所使用的 '{a[$1]+=1;} END {for(i in a){print a[i]" "i;}}' 这段命令中使用了awk中BEGIN、END以及for循环以及数组的相关概念。根据END的作用我们可以将整个命令拆分成两部分,{a[$1]+=1;} 和 {for(i in a){print a[i]" "i;}} ,因为只有在前面部分代码段将我们指定的最后一个输入文件的最后一行处理完之后才会处理END后边的内容。

我们就先讲 {a[$1]+=1;} 这部分
这部分相当于定义了一个数组a,元素名为指定的输入文件的$1的值,元素值为+=1 (这么讲可能不怎么精确,但大致是这个意思)。在处理test.txt文件的时候,因为awk是按行执行的,根据上面test.txt文件中所示的内容。


接下来讲 {for(i in a){print a[i]" "i;}} 这部分
这部分定义了一个for循环,从前面定义的数组a中读取所有的元素名。并打印出来元素的值及加空格分割打印了元素名。 相当于for i in a; do echo "a[i] i"; done 假设数组a的元素名是按照创建先后顺序来排序(根据实际输出结果,可以看出其实是相当于根据大小排序了的,我们这里先这样讲),那么数组a里面会有3个元素192.168.1.3、192.168.1.2、192.168.1.6。

参考《The AWK Programming Language》 P10. Begin与END, P14. For语句, P14. 数组

本篇完.