前言 對於一名專業的程式員來說,Linux相關知識是必須要掌握的,其中對於文本的處理更是我們常見的操作,比如格式化輸出我們需要的數據,這些數據可能會來源於文本文件或管道符,或者統計文本裡面我們需要的數據出現的頻次以及總數等等。那麼這時候awk就很值得我們去學習了。 正文 在Linux中,awk、se ...
前言
對於一名專業的程式員來說,Linux相關知識是必須要掌握的,其中對於文本的處理更是我們常見的操作,比如格式化輸出我們需要的數據,這些數據可能會來源於文本文件或管道符,或者統計文本裡面我們需要的數據出現的頻次以及總數等等。那麼這時候awk就很值得我們去學習了。
正文
在Linux中,awk、sed、grep被稱為“三劍客”,都跟文本操作有關,那他們各自有什麼特點呢?
grep:適合用於單純的查找與匹配。
sed:適合修改匹配到的文本。
awk:適合對文本進行複雜的格式化處理。
所以awk是一種文本處理的編程工具語言,它會掃描輸入數據的每一行,若與當前的pattern匹配,則執行對應的動作,若不匹配或者當前行的動作已執行完成的話則會繼續下一行的處理,直到數據讀取完成。
基本用法
awk基本語法
awk [option] 'pattern{action}' files //awk 關鍵字 //[option] 可以省略的一些參數 //'pattern{action}' pattern 是匹配的條件,可省略。action是具體執行的動作。 //files 是我們操作的文件,可多文件操作。
awk典型用法
awk '{ BEGIN{action ...} //執行前語句 {action...} //匹配處理每行數據 END{action...} //執行後語句 }'
awk內置變數
變數 | 作用 |
---|---|
FS | 輸入欄位分割符,預設空白字元 |
OFS | 輸出欄位分割符,預設空白字元 |
RS | 輸入記錄也就是行數據分隔符,預設換行符 |
ORS | 輸出記錄也就是行數據分隔符,預設換行符 |
NF | 當前行被分割成多少個欄位的數量 |
NR | 當前的行號,從1開始,在多文件中該值也會累加 |
FNR | 當前的行號,從1開始,與NR不同,它是對應各自的文件累加 |
FILENAME | 當前的文件名 |
$0 | 當前行數據 |
$1 ~ $n | 獲取該行記錄的第N個欄位 |
示例:
[root@wangzh awkdemo]# cat /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin ...
//利用FS修改輸入欄位分割符,然後輸出行號以及第1第7個欄位的值 [root@wangzh awkdemo]# awk 'BEGIN{FS=":"} {print NR,$1,$7}' /etc/passwd 1 root /bin/bash 2 bin /sbin/nologin 3 daemon /sbin/nologin 4 adm /sbin/nologin ...
//跟上一個例子的區別,添加了標題的輸出,修改了輸出欄位的分隔符為"-" [root@wangzh awkdemo]#awk 'BEGIN{FS=":";print "Result Title"} {print NR,$1}' OFS="-" /etc/passwd Result Title 1-root 2-bin 3-daemon 4-adm ...
運算符與正則
這塊內容的話,跟我們大多數編程語言都比較相似,大伙可以橫向對比一下,對於剛接觸的同學可以會理解一點。
算術運算符:==,>,<,!=,>=,<=,+,-
邏輯運算符:&&,||
正則:
-
/regex/ 該行內容匹配上正則就執行動作
-
! /regex/ 該行內容未匹配上正則就執行動作
-
$1 ~ /regex/ 只在第一個欄位匹配正則
-
$1 !~ /regex/ 第一個欄位不匹配該正則
案例:
//'-F:' 是定義輸入欄位分割字元的另一種方法,這個匹配第一個欄位包含'root'的信息 [root@wangzh awkdemo]# awk -F: '$1 ~ /root/ {print}' /etc/passwd root:x:0:0:root:/root:/bin/bash dockerroot:x:994:991:Docker User:/var/lib/docker:/sbin/nologin
//輸出第一行到第三行的數據 [root@wangzh awkdemo]# ip addr | awk 'NR>=1 && NR<=3 {print}' 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo
if/for/while
if(condi1){action1} else if(condi2){action2} else{action3} --- for(i=1;i<=NR;i++){ action1; action2; ... } --- while(condi){ action1; ... } 可以看到,用法幾乎跟很多編程語言是一致的,下麵給出一個簡單的示例。 [root@wangzh awkdemo]# cat t1.log 1 aa 3 bb 10 cc 9 dd 5 ee --- //判斷每行第一個欄位是否是3-9之間的數字,然後輸出對應的結果 [root@wangzh awkdemo]# awk '{if($1 ~ /[3-9]/){print "yes"} else {print "no"}}' t1.log no yes no yes yes
內置函數
在awk中,內置函數也不少,幫助我們封裝了一些字元操作、數學操作等,具體的用法還需各位查閱幫助手冊,下麵就先介紹一下比較常用的 sub() 函數的用法。
參考:http://www.cnblogs.com/chengmo/archive/2010/10/08/1845913.html
sub( Ere, Repl, [ string ] )
string參數是需要處理的字元串,預設是$0
也就是當前行
把Ere
正則匹配的字元串用Repl
的字元串來替換
[root@wangzh awkdemo]# awk 'BEGIN{info="this is a test2019test!";sub(/[0-9]+/,"!",info);print info}' this is a test!test!
實戰案例
統計文本中關鍵字出現的次數
[root@wangzh awkdemo]# cat data.txt ID NAME 1 xiaom 2 zsan 3 lisi 4 lisi 5 lisi 6 xiaom 7 lisi 8 xiaom 9 xiaoh 10 zsan
[root@wangzh awkdemo]# awk 'BEGIN{print "Statistics Result >>>>>"} {if(FNR>1){result[$2]+=1}} END{for(i in result){print i,"count:"result[i]} {print "over >>>>"}}' data.txt Statistics Result >>>>> xiaoh count:1 xiaom count:3 zsan count:2 lisi count:4 over >>>>
結語
本篇文章的目的是讓沒接觸這塊內容的同學對文本處理有一個感性的認識,對於掌握awk絕對不是只看就可以學會的,必須要自己動手實踐起來,遇到問題多查手冊,相信很快你也是一個文本處理高手。
---------------------------------------------------------
公眾號博文同步Github倉庫,有興趣的朋友可以幫忙給個Star哦,碼字不易,感謝支持。
https://github.com/PeppaLittlePig/blog-wechat
推薦閱讀
看完本文有收穫?請轉發分享給朋友吧
關註「深夜裡的程式猿」,分享最乾的乾貨