最近多了很多查找編輯文件和分析日志的需求,之前只是淺淺的知道sed,awk大致的用法,這段時間學(xué)下來才發(fā)現(xiàn),sed和awk真是強(qiáng)大。
awk
awk更擅長對文件進(jìn)行分析和列的操作。
條件類型加動作在接文件,這里條件類型加動作為一組,一條命令中可以放多組?;ɡㄌ杮}中支持 print 的格式, if, while, for ,邏輯判斷等等。
$ awk '{pattern + action}' {filenames}
域編輯
例如,在我們需要輸出 test.log 的第一列:
[root@localhost ~]# awk '{print $1}' test.log
192.29.7.26
192.29.7.14
192.26.2.26
192.15.25.26
awk是這樣操作的,讀入有'\n'換行符分割的一條記錄,然后將記錄按指定的域分隔符劃分域,填充域。$0則表示所有域,$1表示第一個域,$n表示第n個域。默認(rèn)域分隔符是"空白鍵" 或 "[tab]鍵",所以$1代表第一列代表IP。
使用-F,可指定分隔符,如:
[root@localhost ~]# awk -F '"' '{print $1}' test.log
192.29.7.26 - - [14/Dec/2015:20:58:18 +0800] POST /praise HTTP/1.1
192.29.7.14 - - [14/Dec/2015:20:58:19 +0800] GET /api HTTP/1.1
192.26.2.26 - - [14/Dec/2015:20:58:19 +0800] GET /api HTTP/1.1
192.15.25.26 - - [14/Dec/2015:20:58:19 +0800] GET /api HTTP/1.1
也可指定打印的分割符,以下打印第一和第四列,使用tab陳列。
[root@localhost ~]# awk '{print $1"\t"$4}' test.log
還有很多:
[root@localhost ~]# awk '/200/' text.log //搜索文件中匹配200字符的行
[root@localhost ~]# awk '{print NR,NF,$1,$NF}' test.log //顯示文件file的當(dāng)前記錄號、域數(shù)和每一行的第一個和最后一個域
[root@localhost ~]# awk '/string/{print "\047 good \047"}{print $1,$2}' test.log //找到匹配對象string,在其后輸出特定符號,/047代表帶引號
[root@localhost ~]# awk 'BEGIN { OFS="%"} {print $1,$2}' test.log //通過輸出%,改變?nèi)罩镜母袷?[root@localhost ~]# awk -F ':' 'BEGIN {print "name,shell"} {print $1","$7} END {print "blue,/bin/nosh"}' //可以在輸入前后加入特定的標(biāo)識,常用于腳本中
合并拆分文件系列:
[root@localhost ~]awk '{ print $0 }' file1 file2 file3>file //醬file1,file2,file3合并成file
awk無需在變量前添加$符號,這是與shell不一樣的地方,上面的例子用到一些變量,在awk中善于運(yùn)用變量會使工具用途大大增加。以下為各變量的含義。
ARGC 命令行變元個數(shù)
ARGV 命令行變元數(shù)組
FILENAME 當(dāng)前輸入文件名
FNR 當(dāng)前文件中的記錄號
FS 輸入域分隔符,默認(rèn)為一個空格
RS 輸入記錄分隔符
NF 當(dāng)前記錄里域個數(shù)
NR 到目前為止記錄數(shù)
OFS 輸出域分隔符
ORS 輸出記錄分隔符
數(shù)組與自定義變量
除了awk的內(nèi)置變量,awk還可以自定義變量。
[root@localhost ~]# awk '{count++;print $1;} END{print count}' test.log
192.29.7.26
192.29.7.14
192.26.2.26
192.15.25.26
4
比如劉老師說想看,每分鐘的請求數(shù),以下可以將每分鐘的請求數(shù)列出:
[root@localhost ~]# awk -F: '{count[$2":"$3]++} END {for (minute in count) print minute, count[minute]}' test.log
20:58 4
使用數(shù)組可以將日志中IP的請求數(shù)統(tǒng)計(jì)出來
[root@localhost ~]# awk '{a[$1]+=1;}END{for(i in a){print a[i]" " i;}}' test.log
復(fù)合表達(dá)式
可以使用&&或||連接多個表達(dá)式,表達(dá)式用()擴(kuò)起
(expr1) && (expr2)
(expr1) ||(expr)
比如需要查看日志中某一時間斷的請求數(shù):
awk '$4>="[01/Dec/2015:15:00:00"&&$4<="[01/Dec/2015:22:00:00"' test.log
IF
和C語言一樣,基本格式是這樣的
if (expression1) {
action1
} else if (expression2) {
action2
} else {
action3
}
來個栗子??
有如下文本,要求:將第一列中重復(fù)的合并為一行,其第二列填入最長地址的那列
0001|hi
0002|dog
0001|It's a good day
0003|cat
0001|nice
0004|linux
得到的結(jié)果應(yīng)為:
0001|It's a good day
0002|dog
0003|cat
0004|linux
代碼:
#!/bash/bin
BEGIN{FS=OFS="|"; i=1;}
{ if(a[$1]==0){b[i]=$1;a[$1]=$2;i++}
if(length(a[$1])}
END{for(j=1;j}
比較代碼:(實(shí)現(xiàn)不全)
awk 'BEGIN{FS=OFS="|"} !(length(a[$1])>length($2)){a[$1]=$2} END{for(i in a)print i,a[i]}' data.txt
解釋:此例中,用了兩個數(shù)組,a用來與$1關(guān)聯(lián),b用來順序記錄,使得在最后打印時是完全按照$1順序打印。條件句首先判斷數(shù)組元素是否是第一次寫入,若非,則比較當(dāng)前$2值和以前儲存的值長度。
功能不全代碼不能順序打印。當(dāng)$1有重復(fù),而$2長度第一次、第二次、第三次是以遞減的方式時,該代碼應(yīng)用得較好。但是,當(dāng)$2各次得到的長度不確定時,代碼不能實(shí)現(xiàn)上述功能。例如:本例中第5行的第二列若比第3行的第二列長度長時,功能不全代碼就不能實(shí)現(xiàn)要求。