您的位置:首页 > 运维架构 > Shell

shell脚本学习:不得不细心之sed和grep,sort和uniq,从细节看“认真”

2011-07-28 17:53 666 查看
今天下午忙了一个下午写一个小脚本,中间出了很多错误,发现有关sort和uniq的细节问题,而且发现了自己写脚本一些小的方面的疏忽,编程是一门讲究严禁的学问,必须一字不差,否则轻则结果错误,重则无法运行。现在把自己的这些毛病总结下!
今天下午的脚本:
写一个脚本:
1、下载文件ftp://192.168.0.254/pub/Files/access_log至/tmp目录;
2、分析并显示/tmp/access_log文件中位于行首的IP中出现次数最多的前5个,并说明每一个出现了多少次;
3、取出/tmp/access_log文件中以http://开头,后面紧跟着一个域名或IP地址的字符串,比如:http://www.linux.com/install/images/style.css 这个串的http://www.linux.com的部分;而后显示出现次数最多的前5个;
要求:第2、3功能各以函数的方式实现;
#aceess_log的文件信息部分如下:
pleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"
192.168.0.191 - - [24/Jul/2011:17:43:17 +0800] "GET /static/image/cr180_dzx//scrolltop.gif HTTP/1.1" 304 - "http://www.linux.com/forum.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"
192.168.0.191 - - [24/Jul/2011:17:43:17 +0800] "GET /uc_server/images/noavatar_small.gif HTTP/1.1" 304 - "http://www.linux.com/forum.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"
192.168.0.191 - - [24/Jul/2011:17:43:17 +0800] "GET /favicon.ico HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"
192.168.0.191 - - [24/Jul/2011:17:43:17 +0800] "GET /forum.php HTTP/1.1" 200 17354 "http://www.linux.com/group.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"
192.168.0.191 - - [24/Jul/2011:17:43:17 +0800] "GET /data/cache/style_2_common.css?o4R HTTP/1.1" 304 - "http://www.linux.com/forum.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"
192.168.0.191 - - [24/Jul/2011:17:43:17 +0800] "GET /data/cache/style_2_forum_index.css?o4R HTTP/1.1" 304 - "http://www.linux.com/forum.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"
192.168.0.191 - - [24/Jul/2011:17:43:17 +0800] "GET /static/js/common.js?o4R HTTP/1.1" 304 - "http://www.linux.com/forum.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"
192.168.0.191 - - [24/Jul/2011:17:43:17 +0800] "GET /static/image/cr180_dzx//bg.jpg HTTP/1.1" 304 - "http://www.linux.com/forum.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"
192.168.0.191 - - [24/Jul/2011:17:43:17 +0800] "GET /static/image/diy/panel-toggle.png HTTP/1.1" 304 - "http://www.linux.com/forum.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13"

我们的目的是要抓取指定的信息并且排名,这样肯定要用到正则表达式,而且是三个比较长的正则表达式,对正则表达式的书写有一定的要求,我在书写这三个正则表达式时,遇到了很多问题,根据题目的要求要用到sed命令把指定的内容抓出来并替换掉,而我出现了如下错误
1正则表达式最后忘了加 .* 这样对这么长的行起不到替换的作用
2在sed命令抓取后,有一些不符合要求的项也显示出来,这使用可以使用grep “http://” 去掉这些没用的行(我在这一步耽误了很长时间)
3\{ \} 写成了\{ }\ 属于笔误,但书写较长的正则表达式是,这样的错误不可原谅,所以一定要实现把这些需要转移的括号给完成,然后在写要匹配的内容,以免错误的发生。
4 sed 命令忘了写 ‘’中的一个,应该实现就写好‘’避免遗忘以出错
我的第二个函数如下
function URL {
   sed '1,$s@.*\(http://[a-zA-Z]\{1,\}\.[a-zA-Z]\{1,\}\.[a-zA-Z]\{1,\}\).*@\1@g' /tmp/access_log | grep "^http://" > /tmp/tt.1
   sed '1,$s@.*\(http://[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\).*@\1@g' /tmp/access_log | grep "^http://" >> /tmp/tt.1
   echo -e "  \033[33mTIMES   Doman\033[0m  \033[5;32m<---------Here is the doman rank\033[0m"
   sort /tmp/tt.1 | uniq -c | sort -rn | head -5
}
很明显,这样长的正则表达式很容易出错,希望以后在书写sed 命令和正则表达式以及其他的命令时能吸取教训。
sort和uniq
这两个命令有一些特别容易忽视的问题,比如uniq命令 当使用sourt -n时,它并不是以数字大小比较,而是以首字符大小比较!(千万注意)所以,应该使用sort -rn来用数字排序。 而uniq 在处理特别的数据时,如果不用sort事先处理的话,会出现不是自己想要的结果,如下:
[root@dean 725-27]# sed '1,$s@.*\(http://[a-zA-Z]\{1,\}\.[a-zA-Z]\{1,\}\.[a-zA-Z]\{1,\}\).*@\1@g' /tmp/access_log | grep "^http://" | uniq -c
      2 http://www.baidu.com                    //baidu在下面又出现了!
  11983 http://www.linux.com       1 http://i.ifeng.com    3761 http://www.linux.com       4 http://www.baidu.com                    //重复出现!
这是因为uniq的处理机制,并不是合并全部重复的,而是连续重复的!所以正确的使用方法应该是,先将要处理的文件用sort先排序,将他们重复的排序在一起,然后用uniq处理
sort   file | uniq -c  | sort -rn
实现排序

整个脚本的代码如下:
#!/bin/bash
cd /tmp
wget ftp://192.168.0.254/pub/Files/access_log echo -e "\033[32mdownload secessfull!\033[0m "
echo "---------------------------------------"
FILE=/tmp/access_log
function IP {
echo -e " \033[33mTIMES IP\033[0m \033[5;32m<------------ Here is the ip rank\033[0m"
awk '{print $1}' $FILE | sort | uniq -c | sort -rn | head -5
}
function URL { sed '1,$s@.*\(http://[a-zA-Z]\{1,\}\.[a-zA-Z]\{1,\}\.[a-zA-Z]\{1,\}\).*@\1@g' /tmp/access_log | grep "^http://" > /tmp/tt.1 sed '1,$s@.*\(http://[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\).*@\1@g' /tmp/access_log | grep "^http://" >> /tmp/tt.1 echo -e " \033[33mTIMES Doman\033[0m \033[5;32m<---------Here is the doman rank\033[0m" sort /tmp/tt.1 | uniq -c | sort -rn | head -5
}
IP
URL
rm -f /tmp/tt.1

##总结:在书写shell脚本的时候,一定要先思考命令的用法,在明确命令的书写格式和用法时先写那些容易出错的地方,避免书写错误。其他的需要注意的方面,比如,if语句最后的fi, if 右面紧跟的then , 循环体后的done ,最后删除缓存文件,case语句没条结束时的;; 最后的*)而不是‘*’) ,还有最后的esac等等
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: