1. 题目

有日志 1.log,部分内容如下:

112.111.12.248 - [25/Sep/2013:16:08:31 +0800]formula-x.haotui.com  "/seccode.php?update=0.5593110133088248" 200"http://formula-x.haotui.com/registerbbs.php" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)"
61.147.76.51 - [25/Sep/2013:16:08:31 +0800]xyzdiy.5d6d.com "/attachment.php?aid=4554&k=9ce51e2c376bc861603c7689d97c04a1&t=1334564048&fid=9&sid=zgohwYoLZq2qPW233ZIRsJiUeu22XqE8f49jY9mouRSoE71" 301"http://xyzdiy.×××thread-1435-1-23.html" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"

请统计出每个IP的访问量是多少?

2. 题目分析

根据日志内容,可以看到IP地址就是第一段的内容,所以只需把1.log的第一段给过滤出来,然后进一步统计每个IP的数量即可。

过滤第一段,使用awk就可以了,而统计每个IP的访问量则需要排序然后再计算数量,排序使用sort命令,统计每个IP的访问量用uniq。

3. 具体shell命令

这道题,用shell脚本一条命令就足够了:

awk  '{print  $1}'  1.log | sort   -n  | uniq  -c | sort  -n

解释:

  1. awk 命令在分段方面比较有优势,这里的{print $1}将第一段打印出来,awk可以用-F指定分隔符,如果不指定分隔符,默认就以空白字符(比如空格、tab等),本题中,IP地址就是第一段。
  2. sort 命令就是排序,-n选项表示以数字的形式排序。如果不加-n,则以ASCII排序,本题的IP地址用数字的形式排序更易区分。
  3. uniq 命令用来去重复,一个文本如果有多行内容是一模一样的,就使用uniq命令将相同的内容删除,只保留一行。-c选项作用是计算重复的行数。所以,uniq -c 的作用正好就统计了ip的访问量。不过,要注意,uniq去重要在排序之后进行。
  4. 最后的sort -n意思是按访问量大小来排序,请求量越大的ip排在越后面。如果加一个-r选项,sort -nr,就是倒序排序。

4. 结语

这道题目还有另一种解法,明天再更新吧。

补充于4月11日
由于这篇文章在题目的例子里有一些IP连接,所以每次修改发文官方都要重新审核一天,我就不重新再写一篇文章来写另一种方法了。

这种方法最主要的区别,就是使用了awk的数组来统计结果,请看命令:

awk '{sum[$1]+=1};END{ for( a in sum)print (sum[a], a)}' 1.log | sort -nr | head -n 5

解释一下,这条命令中$1 就表示日志中的IP地址,用IP地址作为数组的下标,每发现一个相同的IP地址,就统计数量加1;当awk遍历日志文件1.log 完毕,再循环输出数组 sum 的结果,要注意数组的下标是 ip地址。

后面的 head -n 5 是为了输出出现访问次数最高的5个访问ip地址。