“ 最近開始用kpt記錄自己的日常工作,本文將是該系列的第一篇,主要講解linux下如何快速邏輯處理數據”
Keep
正在做日志篩選數據的事情,需要從服務日志中撈出含關鍵字的日志,并且該條日志中含響應時間數據,需撈出其中大于500ms的數據
Problem
普通的grep只能撈出所有包含關鍵字的日志,沒法做一些簡單的邏輯判斷,如果用編程語言來處理又會顯得很笨重
Try
linux下有一個利器命令awk可以使用;
對于test.log日志內容類似如下的:
2019-05-03 20:00:00 requestId:a1 bb cc dd 465 2019-05-03 20:00:01 requestId:aa bb cc kkk 2019-05-03 20:00:01 requestId:a2 bb cc dd 502 2019-05-03 20:00:01 requestId:a3 bb cc dd 600
上述內容中數字表示響應時間,如果需要打印響應時間大于500的requestId的值,基于awk該怎么寫:
cat test.log |grep dd|awk '$7>500 {print $3}'
接下來讓我們帶著疑問來學習入門下awk命令:
awk 'BEGIN{ commands } pattern{ commands } END{ commands }' # 這是awk的標準格式,BEGIN和END是可選的 # 1、通過關鍵字 BEGIN 執行 BEGIN 塊的內容,即 BEGIN 后花括號 {} 的內容。 # 2、完成 BEGIN 塊的執行,開始執行body塊。 # 3、讀入有 n 換行符分割的記錄。 # 4、將記錄按指定的域分隔符劃分域,填充域,$0 則表示所有域(即一行內容),$1 表示第一個域,$n 表示第 n 個域。 # 5、依次執行各 BODY 塊,pattern 部分匹配該行內容成功后,才會執行 awk-commands 的內容。 # 6、循環讀取并執行各行直到文件結束,完成body塊執行。 # 7、開始 END 塊執行,END 塊可以輸出最終結果。
重新來分析下上面寫awk命令
cat test.log |grep dd|awk '$7>500 {print $3}' # 先通過grep獲取到所有包含dd的內容 # 接下來使用awk命令,這里直接用body模塊,處理每一行數據 # awk默認的分割符剛好是空格,所以我們直接用$7可以直接拿到響應時間 # 判斷完后簡單多了,我們直接$3拿到每一個requestId # 如果吹毛求疵下,只想拿到對應的requestId的值該怎么寫? cat test.log |grep dd|awk '$7>500 {print $3}'|awk -F:'{print $2}' # 我們在上述命令基礎上再加上管道符,并利用-F來指定新的分隔符:,剛好將requestId:a1這樣的字符串切割成兩個 # 然后直接print $2即可
一些awk的高級用法
正則匹配:
cat test.log |awk '/dd/ && $7>500 {print $3}'|awk -F: '{print $2}' # awk命令支持正則匹配,所以上述解決方案中,其實不需要grep命令,直接按照上述編寫即可,&&表示并且
if函數:
cat test.log |awk '/dd/ {if($7>500)print $3}'|awk -F: '{print $2}' # awk自帶if函數,上述解決方案我們還可以這樣編寫。將if函數放到body的{}中
BEGIN的用法:
END的用法
cat test.log |awk 'BEGIN {print "im begin"} /dd/&&$7>500 {num=num+1;total=total+$7} END {print num;print total}' # awk支持自定義變量,上述命令是統計響應時間大于500的日志記錄數,以及累計響應時長 # 我們也可以先在BGGIN模塊初始化自定義變量 cat test.log |awk 'BEGIN {print "im begin";num=0;total=0} /dd/&&$7>500 {num=num+1;total=total+$7} END {print num;print total}'
參考資料:
https://www.runoob.com/linux/linux-comm-awk.html
https://coolshell.cn/articles/9070.html