前言
這兩天自己挽起袖子處理日志,終於把AWK給入門了。其實AWK的基本使用,學起來也就半天的時間,之前總是靠同事代勞,惰性呀。
此文僅為菜鳥入門,運維們請勿圍觀。
下面是被處理的日志的示例,不那么標准,但不標准的日志正是標准的情況。
[2015-08-20 10:00:55.600] - [192.168.0.73/192.168.0.75:1080 com.vip.xxx.MyService_2.0 0 106046 100346 90ms 110ms]
基本語句
最基本的語句,以空格做分割,提取所需的列:
awk '{print $0,$1,$2,$(NF-1),$NF,$NF-$(NF-1)}’ access.log
1. 輸入
AWK是針對文件或管道中每行輸入的處理語言。所以也可以從管道輸入:
grep “xxx” access.log | awk '{print $1}’
但下面這樣寫就會成為一個Linux老梗的主角,awk不需要不需要cat的。
cat access.log | awk '{print $1}'
2.語句定義
可以快速的用單引號’ ’,把所有語句寫成一行。
也可以用-f 指定文件,文件里可以任意換行,增加可讀性和重用性。
所有執行語句用{}括起來,{}的外面是一些高級的東西比如過濾條件,見后。
3. 列引用
$0代表整行所有數據,$1代表第一列(終於不是程序員數數從0開始了)。
NF是個代表總列數的系統變量,所以$NF代表最后一列,還支持$(NF-1)來表示倒數第二列。
還支持列之間的運算,如$NF-$(NF-1)是最后兩列的值相減。
只寫一個print 是 print $0的簡寫,打印整行所有數據。
4. 輸入的列分隔符
默認以空格做分割符,也可以重新指定,下例指定了':'
awk -F ':' '{print $1,$2}’ access.log
也可以正則表達式定義多個分割符,下例指定了 '-' 和 ':'
awk -F '[-:]' '{print $1,$2}’ access.log
5. 輸出的列間隔
print $1,$2 中間的','逗號,代表打印時第1與第2列之間使用默認分隔符號也就是空格,也可以用” ”來定義其他任意的字符:
awk '{print $1 "\t" $2 " - " $3$4xxxxx$5}’ access.log
上例,在第1第2列之間用 tab 分隔,第2第3列之間用" - "分隔,
也可以什么都不寫代表中間沒分隔,比如第3第4列之間,或者亂寫一些字符沒用" "括起來,也等於沒寫,比如第4第5列之間。
數字類型,字符串類型
雖然上例最后兩列的值是字符串類型的,帶着ms字樣,看起來不能做算術運算。
但其實兩個列相減時,AWK就會神奇地把它們轉換為純數字。同樣,做累計的時候,sum=sum+$NF,也能自動轉換為數字。
如果想對某個字符列比較是否大於閥值,先把它轉回數字就行了,上一篇文章里的
sed "s|ms]||g" access.log | awk ' $NF>100 {print}'
其實可以簡寫成下面的樣子,性能還比使用sed略快:
awk ' $NF*1>100 {print}’ access.log
或
awk ' int($NF)>100 {print}’ access.log
BEGIN與END語句
BEGIN與END后的語句定義在處理全部文本內容之前與之后的語句。
1.計算累計值和平均值
awk '{sum+=$NF} END {print sum, sum/NR}'
上例對每行輸入內容進行最后一列的值的累計,而END后的語句,打印累計結果 和平均值,NR是系統變量代表總行數。
2.打印表頭
還可以定義BEGIN語句打印表頭,定義變量什么的。
awk 'BEGIN{print "Date\t\tTime\t\tCost”} {print $1 "\t"$2 "\t" $NF}’ access.log
上例表頭用兩個制表符分隔,內容則用一個制表符分隔,有良好的對齊效果。
過濾行
1. 簡單字符匹配
先用grep過濾也是可以的,也可以用awk簡單在執行語句之外的/ /之間定義正則表達式
awk '/192.168.0.4[1-5]/ {print $1}’ access.log
等價於
grep "192.168.0.4[1-5]” access.log| awk ‘{print $1}
2. 針對某一列的字符匹配
針對第4列的地址段匹配,~ 是字符匹配,!~則是不匹配的意思。
awk '$4 ~ /192.168.0.4[1-5]/ {print}'
3. 針對數值的過濾
支持==, !=, <, >, <=, >=
awk '$(NF-1)*1==100 {print}'
awk '$NF-$(NF-1)>100 {print}'
見前,對於非純數字的字段,可以用算術運算讓它轉回數字。
4. 多條件同時存在
awk '($12 >150 || $(13)>250) {print}'
5. 使用if語句
如果邏輯更復雜,可以考慮使用if,else等語句
awk '{ if ($(NF-1)*1>100) print}'
其他
1.外部傳入參數
比如從外面傳入超時的閥值,注意threshold在命令行中的位置。
awk '{if($(NF)*1>threshold) print}' threshold=20 access.log
2.常用函數
最有用是gsub和sub,match,index等。其中gsub將一個字符串替換為目標字符串,可選定整行替換或只替換某一列。
awk '{gsub("ms]","",$NF); if( $NF>100 ) print}' access.log
一些例子
1.截取日期段內段數據
方式有很多,都是隨着日志格式不同自由發揮。
比如下段截取17:30:30 秒到 17.31:00的數據,先抽取出時分秒三列,再拼成一個數字進行比較
awk -F "[ :.]" '$2$3$4>=173030 && $2$3$4<173100 {print}'
也可以匹配某個整點時間, 下例取11點的日志:
awk '/[2015-08-20 11:/ {print $1}’ access.log
取11點01分到05分的數據:
awk '/[2015-08-20 11:0[1-5]:/ {print $1}’ access.log
2. 找出超時的數據集中發生的時間
第一段找出超時記錄,第二段過濾掉時間戳里的微秒,然后按秒來合並,並統計該秒超時的次數。
awk '$(NF)*1>100 {print}’ access.log | awk -F"." '{print $1}' | sort | uniq -c
原文地址:http://calvin1978.blogcn.com/articles/awk_accesslog.html