awk分类统计

前些时间去面试,其中又这么一道题:写一个脚本,统计一下apache日志中IP出现频率最高的前五个。
当时就懵了。apache日志,大爷的,好歹给个例子,让我看看apache日志长什么样子。
没办法,只得动用我正则表达式的储备了,于是,尝试使用正则表达式来解决问题。

简略分析下,分为这么几步:
首先,把IP地址过滤出来,可以使用
      grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"
然后,使用sed把包含IP地址的给搞出来,这里肯定要用到分组
      sed '/.*\("[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"\).*/\1/'
最后是,统计每个IP地址出现的频率,并把IP地址和频率打印出来
     awk '{s[$0]++}END{for(i in s)print i,s[i]}'
还有一步,就是按照频率逆序排列,并取前五行
      sort -k2nr | head -5

把语句连起来,组合调试一下
 cat File_Name | grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" |  \
 sed 's/.*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/' | \
 awk '{s[$0]++}END{for(i in s)print i,s[i]}' | \
 sort -k2nr | head -5
 
然后,编写一个文件,名字就叫做 test.lst ,里面随便写点东西:
10.2.3.4 dsjakld
10.2.3.4 dsjakld
10.2.3.5 dsjakld
10.2.3.4 dsjakld
10.2.3.4 dsjakld
10.4.3.4 dsjakld
10.2.3.1 dsjakld
10.2.3.4 dsjakld
10.2.3.4 dsjakld
10.4.3.1 dsjakld
10.2.3.4 dsjakld
10.2.3.4 dsjakld
10.2.2.1 dsjakld
10.2.3.4 dsjakld
10.4.3.4 dsjakld

把语句帖进来执行试试看:
[root@bogon ~]# cat test.lst | grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" |  \
>  sed 's/.*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/' | \
>  awk '{s[$0]++}END{for(i in s)print i,s[i]}' | \
>  sort -k2nr | head -5
0.2.3.4 9
0.4.3.4 2
0.2.2.1 1
0.2.3.1 1
0.2.3.5 1

好奇怪,IP地址明明是 10开头,为毛变成了 0. 
仔细想想,知道了,是 * 惹的祸,改造下:
[root@bogon ~]# cat test.lst | grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" |  \
> sed 's/[^0-9]*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)[^0-9]*/\1/' | \
> awk '{s[$0]++}END{for(i in s)print i,s[i]}' | \
> sort -k2nr | head -5
10.2.3.4 9
10.4.3.4 2
10.2.2.1 1
10.2.3.1 1
10.2.3.5 1

似乎没问题了。也许还潜藏着别的BUG,不过就目前而言,是瞒着要求了。
先这么着的,略微优化一下,或者说改变一下:
cat test.lst | grep "[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}" |  \
sed 's/[^[:digit:]]*\([[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\)[^[:digit:]]*/\1/' | \
awk '{s[$0]++}END{for(i in s)print i,s[i]}' | \
sort -k2nr | head -5

再一想,我好想没必要把那些行先过滤出来,直接替换就是了:
cat test.lst | sed 's/[^[:digit:]]*\([[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\)[^[:digit:]]*/\1/' | \
awk '{s[$0]++}END{for(i in s)print i,s[i]}' | \
sort -k2nr | head -5


 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值