今天下午忙了一個下午寫一個小指令碼,中間出了很多錯誤,發現有關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"
我們的目的是要抓取指定的資訊並且排名,這樣肯定要用到Regex,而且是三個比較長的Regex,對Regex的書寫有一定的要求,我在書寫這三個Regex時,遇到了很多問題,根據題目的要求要用到sed命令把指定的內容抓出來並替換掉,而我出現了如下錯誤
1Regex最後忘了加 .* 這樣對這麼長的行起不到替換的作用
2在sed命令抓取後,有一些不符合要求的項也顯示出來,這使用可以使用grep “http://” 去掉這些沒用的行(我在這一步耽誤了很長時間)
3\{ \} 寫成了\{ }\ 屬於筆誤,但書寫較長的Regex是,這樣的錯誤不可原諒,所以一定要實現把這些需要轉移的括弧給完成,然後在寫要匹配的內容,以免錯誤的發生。
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
}
很明顯,這樣長的Regex很容易出錯,希望以後在書寫sed 命令和Regex以及其他的命令時能吸取教訓。
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/bashcd /tmpwget ftp://192.168.0.254/pub/Files/access_logecho -e "\033[32mdownload secessfull!\033[0m "echo "---------------------------------------"FILE=/tmp/access_logfunction 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}IPURLrm -f /tmp/tt.1
##總結:在書寫shell指令碼的時候,一定要先思考命令的用法,在明確命令的書寫格式和用法時先寫那些容易出錯的地方,避免書寫錯誤。其他的需要注意的方面,比如,if語句最後的fi, if 右面緊跟的then , 迴圈體後的done ,最後刪除快取檔案,case語句沒條結束時的;; 最後的*)而不是‘*’) ,還有最後的esac等等