/blog/2009/11/an_autobiography_of_yang_xianyi.html
考虑到我们只统计成功的请求,因此再加一个限制条件,服务器的状态代码必须是200(表示成功),写成\200\,即第9个字段必须是200,否则不输出第7个字段。 更精细的统计,还应该区分网络蜘蛛和真实访问者,由于我想不出简单的分辨方法,这里只好忽略了。 (2)grep -i '^/blog/2011/.*\\.html$'
在输出的所有记录的第7个字段之中,并不是每一条记录都需要统计的。根据我的文章的命名特点,它们的网址应该都以\开头,以\结尾。所以,我用一个正则表达式\,找出这些记录。参数i表示不区分大小写。 (3)sort
这时,所有需要统计的记录应该都列出来了,但是它们的次序是杂乱的。接着,使用sort命令,不过目的不是为了排序,而是把相同的网址排列在一起,为后面使用uniq命令创造条件。 (4)uniq -c
uniq的作用是过滤重复的记录,只保留一行。c参数的作用,是在每行的开头添加该记录的出现次数。处理之后的输出应该是这样的: 32
/blog/2011/01/guidelines_for_english_translations_in_public_places.html 32
/blog/2011/01/api_for_google_s_url_shortener.html 30
/blog/2011/01/brief_history_of_arm.html 它表示以上三篇文章,在1月1日的日志中,分别有32条、32条、30条的访问记录(即访问次数)。 (5)sed 's/^ *//g' > www-01.log.result
上一步uniq命令添加的访问次数,是有前导空格的。也就是说,在上例的32、32、30之前有一连串空格,为了后续操作的方便,这里把前导空格删去。sed命令是一个处理行文本的编辑器,'s/^ *//g'是一个正则表达式(^和*之间有一个空格),表示将行首的连续空格替换为空(即删除)。接着,将排序结果重定向到文件www-01.result。单个日志分析就完成了。
五、月度汇总排名
经过上一步之后,1月份的31个日志文件,生成了31个对应的分析结果文件。为了汇总整个月的情况,必须把这31个结果文件合并。 (6)合并分析结果
for i in www-*.log.result do
cat $i >> log.result done
这是一个循环结构,把所有www-01.log.result形式的文件,都写进log.result文件。
然后,我用一行语句,计算月度排名。 sort -k2 log.result | uniq -f1
--all-repeated=separate |./log.awk |sort -rn > final.log.result
这行语句由3个命令和1个awk脚本组成: (7)sort -k2 log.result
由于是31个文件汇总,log.result文件里面的记录是无序的,必须用sort命令,将相同网址的记录归类在一起。
但是此时,访问次数是第一个字段,网址是第二个字段,因此参数k2表示根据第二个字段进行排序。 (8)uniq -f1 --all-repeated=separate
uniq的作用是过滤重复的记录,参数f1表示忽略第一个字段(访问次数),只考虑后面的字段(网址);参数表示all-repeated=separate,表示过滤掉所有只出现一次的记录,保留所有重复的记录,并且每一组之间用一个空行分隔。这一步完成以后,输出结果变成如下的形式: 617
/blog/2011/01/guidelines_for_english_translations_in_public_places.html 455
/blog/2011/01/guidelines_for_english_translations_in_public_places.html 223
/blog/2011/01/2010_my_blogging_summary.html 253
/blog/2011/01/2010_my_blogging_summary.html 相同网址都归在一组,组间用空行分割。为了简洁,上面的例子每一组只包含两条记录,实际上每一组都包含31
条记录(分别代表当月每天的访问次数)。 (9)log.awk脚本
为了将31天的访问次数加总,我动了很多脑筋。最后发现,唯一的方法就是用awk命令,而且必须另写一个awk脚本。
#!/usr/bin/awk -f BEGIN {
RS=\将多行记录的分隔符定为一个空行 } {
sum=0 #定义一个表示总和的变量,初值为0 for(i=1;i<=NF;i++){ #遍历所有字段 if((i%2)!=0){ #判断是否为奇数字段 sum += $i #如果是的话,累加这些字段的值 } }
print sum,$2 #输出总和,后面跟上对应的网址 }