程式猿必知必會Linux命令之awk

深夜裡的程式猿發表於2019-04-24

前言

對於一名專業的程式設計師來說,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() 函式的用法。

參考:www.cnblogs.com/chengmo/arc…

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哦,碼字不易,感謝支援。

github.com/PeppaLittle…

推薦閱讀

Java日誌正確使用姿勢
使用ConcurrentHashMap一定執行緒安全?
大白話搞懂什麼是同步/非同步/阻塞/非阻塞
論JVM爆炸的幾種姿勢及自救方法

有收穫的話,就點個贊吧

關注「深夜裡的程式猿」,分享最乾的乾貨

程式猿必知必會Linux命令之awk

相關文章