Shell三劍客之a(chǎn)wk
1. awk概述
1.1 awk是什么
awk不同于grep的文本搜索與sed工具的文本處理,它更偏向于對文本的格式化處理輸出,它不僅僅是一款工具,也是一門解釋性語言,其名字來源于它的三位作者的姓氏:Alfred Aho, Peter Weinberger 和 Brian Kernighan,在文本處理功能非常強大,是一款Linux服務(wù)器文本報告生成器和格式化文本輸出工具。
1.2 為什么用awk
我們?nèi)粘9ぷ髦杏泻芏嘈枰袷交蛴≥敵龅男枨螅嗟氖顷P(guān)注列操作時,就可以利用awk工具來進行處理。awk除了是工具也同樣是一門語言,其允許用戶創(chuàng)建簡短的程序來處理自己的需求,這些程序讀取輸入文件、為數(shù)據(jù)排序、處理數(shù)據(jù)、對輸入執(zhí)行計算以及生成報表等。功能非常的強大,相信在掌握了awk,日常運維工作更加方便高效簡單。
2. awk的適用場景
- 超大文件處理;
- 輸出格式化的文本報表;
- 執(zhí)行算數(shù)運算;
- 執(zhí)行字符串操作等。
3. awk的處理模式
一般是遍歷一個文件中的每一行,然后分別對文件的每一行進行處理。
awk對輸入的一行數(shù)據(jù)進行處理的模式,對整個文件進行重復(fù)執(zhí)行此模式處理,在此說明對輸入的一行數(shù)據(jù)處理的內(nèi)在機制如下圖所示:

處理過程不斷重復(fù),直到到達文件結(jié)尾。
- 首先讀入文件流的一行到模式空間;
- 在模式空間內(nèi),對內(nèi)容進行模式匹配處理;
- 然后輸出處理后的數(shù)據(jù)內(nèi)容;
- 清空當(dāng)前模式空間;
- 讀取第二行輸入流到模式空間;
- 又開始對模式空間內(nèi)的第二行輸入數(shù)據(jù)進行處理。
總體可以分為以下三步:
-
讀(Read):AWK 從輸入流(文件、管道或者標(biāo)準(zhǔn)輸入)中讀入一行然后將其存入內(nèi)存中。
-
執(zhí)行(Execute):對于每一行輸入,所有的 AWK 命令按順序執(zhí)行。 默認(rèn)情況下,AWK 命令是針對于每一行輸入,但是我們可以將其限制在指定的模式中。
-
重復(fù)(Repeate):一直重復(fù)上述兩個過程直到文件結(jié)束。
4. 語法及結(jié)構(gòu)
4.1 語法
Awk 語法格式如下圖所示:

awk [options] 'PATTERN {action}' file1,file2
awk 的語法格式主要分為四個字段,options 選項,引號內(nèi)有模塊與動作,以及要處理的文件,接下來讓我們詳細講解每一個語法字段,更全面地認(rèn)識 awk 這個腳本利器。
4.2 程序結(jié)構(gòu)
awk 在引號內(nèi)有一定的程序結(jié)構(gòu),主要為以下:
- 開始塊(BEGIN BLOCK):
語法:
BEGIN{awk-commands}
開始塊就是awk程序啟動時執(zhí)行的代碼部分(在處理輸入流之前執(zhí)行),并且在整個過程中只執(zhí)行一次;
一般情況下,我們在開始塊中初始化一些變量。BEGIN是awk的關(guān)鍵字,因此必須要大寫。【注:開始塊部分是可選,即你的awk程序可以沒有開始塊部分】
- 主體塊(Body Block):
語法:
/pattern/{awk-commands}
針對每一個輸入的行都會執(zhí)行一次主體部分的命令,默認(rèn)情況下,對于輸入的每一行,awk都會執(zhí)行主體部分的命令,但是我們可以使用/pattern/限制其在指定模式下。
- 結(jié)束塊(END BLOCK):
語法:
END{awk-commands}
結(jié)束塊是awk程序結(jié)束時執(zhí)行的代碼(在處理完輸入流之后執(zhí)行),END也是awk的關(guān)鍵字,必須大寫,與開始塊類似,結(jié)束塊也是可選的。
4.3 awk命令詳解
4.3.1 awk 輸出
- awk print輸出,例如:
print item1,item2...
1.各字段之間逗號隔開,輸出時以空白字符分隔;
2.輸出的字段可以為字符串或數(shù)值,當(dāng)前記錄的字段(如$1)、變量或 awk 的表達式;數(shù)值先會轉(zhuǎn)換成字符串然后輸出;
3.print 命令后面的 item 可以省略,此時其功能相當(dāng)于print $0
,如果想輸出空白,可以使用print ""
;
例如:
[root@master ~]# awk -F: '{print $1,$NF}' /etc/passwd|column -t
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
- awk printf 輸出
printf 命令的使用格式:
printf <format> item1,item2...
要點:
1.其與 print 命令最大區(qū)別,printf 需要指定 format,format 必須給出;
2.format 用于指定后面的每個 item 輸出格式;
3.printf 語句不會自動打印換行字符\n
。
format 格式的指示符都以 % 開頭,后跟一個字符:
%c:顯示ascall碼
%d:%i:十進制整數(shù)
%e,%E:科學(xué)計數(shù)法
%f:浮點數(shù)
%s:字符串
%u:無符號整數(shù)
%%:顯示%自身
修飾符:
#[.#]:第一個#控制顯示的寬度:第二個#表示小數(shù)點后的精度:
%3.1f
-:左對齊
+:顯示數(shù)組符號
例如:
[root@master ~]# awk -F: '{printf "Username:%-15s ,Uid:%d\n",$1,$3}' /etc/passwd
Username:root ,Uid:0
Username:bin ,Uid:1
Username:daemon ,Uid:2
Username:adm ,Uid:3
Username:lp ,Uid:4
Username:sync ,Uid:5
Username:shutdown ,Uid:6
4.3.2 awk變量
-
記錄變量:
- IFS(input field separator),輸入字段分隔符(默認(rèn)空白)
- OFS(output field separator),輸出字段分隔符
- RS(Record separator):輸入文本換行符(默認(rèn)回車)
- ORS:輸出文本換行符
-
數(shù)據(jù)變量
- NR:the number of input records,awk 命令所處理的文件的行數(shù),如果有多個文件,這個數(shù)目會將處理的多個文件計數(shù)
- NF:number of field,當(dāng)前記錄的 field 個數(shù)
{print NF},{print $NF}
-
ARGV:數(shù)組,保存命令行本身這個字符串
-
ARGC:awk 命令的參數(shù)個數(shù)
-
FILENAME:awk 命令處理的文件名稱
-
ENVIRON:當(dāng)前 shell 環(huán)境變量及其值的關(guān)聯(lián)數(shù)組
awk 'BEGIN{print ENVIRON["PATH"]}'
-
自定義變量
-v var=value
變量名區(qū)分大小寫,例如:
[root@master ~]# awk -v test="abc" 'BEGIN{print test}' abc [root@master ~]# awk 'BEGIN{var="name";print var}' name
4.3.3 操作符
-
算術(shù)運算
- +,-,*,/,^,%。例如:
[root@master ~]# awk 'BEGIN{a=5;b=3;print "a + b =",a+b}' a + b = 8
-
字符串操作
- 無符號操作符,表示字符串連接,例如:
[root@master ~]# awk 'BEGIN { str1="Hello,"; str2="World"; str3 = str1 str2; print str3 }' Hello,World
-
賦值操作符:
- =,+=,-=,*=,/=,%=,^=,例如:
[root@master ~]# awk 'BEGIN{a=5;b=6;if(a == b) print "a == b";else print "a!=b"}' a!=b [root@master ~]# awk -F: '{sum+=$3}END{print sum}' /etc/passwd 72349
-
比較操作符:
- >,>=,<,<=,!=,==
-
模式匹配符:
- ~:是否匹配
- !~:是否不匹配
例如:
[root@master ~]# awk -F: '$1~"root"{print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash
-
邏輯操作符:
- && 、 || 、 !,例如:
[root@master ~]# awk 'BEGIN{a=6;if(a > 0 && a <= 6) print "true";else print "false"}' true
-
函數(shù)調(diào)用:
- function_name(argu1,augu2)
-
條件表達式(三元運算):
- selection?if-true-expresssion:if-false-expression
[root@master ~]# awk -F: '{$3>=100?usertype="common user":usertype="sysadmin";printf "%15s:%s\n",$1,usertype}' /etc/passwd root:sysadmin bin:sysadmin daemon:sysadmin adm:sysadmin lp:sysadmin sync:sysadmin shutdown:sysadmin halt:sysadmin
4.3.4 Pattern
- empty:空模式,匹配每一行
- /regular expression/:僅處理能被此處模式匹配到的行,例如;
[root@master ~]# awk -F: '$NF=="/bin/bash"{printf "%15s,%s\n",$NF,$1}' /etc/passwd
/bin/bash,root
- relational expression:關(guān)系表達式,結(jié)果為“真”有“假”,結(jié)果為“真”才會被處理。
Tips:使用模式需要使用雙斜線括起來,真:結(jié)果為非0值,非空字符串。
[root@master ~]# awk -F: '$3>100{print $1,$3}' /etc/passwd
systemd-network 192
polkitd 999
ceph 167
kube 998
etcd 997
gluster 996
nfsnobody 65534
chrony 995
redis 994
awk -F: '$NF=="/bin/bash"{printf "%15s,%s\n",$NF,$1}' /etc/passwd
awk -F: '$NF~/bash$/{printf "%15s,%s\n",$NF,$1}' /etc/passwd
df -Th|awk '/^\/dev/{print}'
-
line ranges:行范圍,制定startline,endline。
[root@master ~]# awk -F: '/10/,/20/{print $1}' /etc/passwd games ftp nobody systemd-network dbus polkitd postfix sshd ceph kube etcd gluster rpc
-
BEGIN/END模式
- BEGIN{}:僅在開始處理文本之前執(zhí)行一次
- END{}:僅在文本處理完成之后執(zhí)行一次
[root@master ~]# awk -F: 'BEGIN{print "username uid\n--------------------"}{printf "%-15s:%d\n",$1,$3}END{print "-----------------\nend"}' /etc/passwd
username uid
--------------------
root :0
bin :1
daemon :2
adm :3
lp :4
rpc :32
rpcuser :29
nfsnobody :65534
chrony :995
redis :994
-----------------
end
4.3.5 控制語句
- if(condition) {statements},例如:
[root@master ~]# awk -F: '{if($3>100) print $1,$3}' /etc/passwd
systemd-network 192
polkitd 999
ceph 167
kube 998
etcd 997
gluster 996
nfsnobody 65534
chrony 995
redis 994
- if(condition) {statments} [else {statments}],例如:
[root@master ~]# awk -F: '{if($3>100) {printf "Common user:%-15s\n",$1} else {printf "sysadmin user:%-15s\n",$1}}' /etc/passwd
sysadmin user:root
sysadmin user:bin
sysadmin user:daemon
sysadmin user:adm
sysadmin user:lp
sysadmin user:sync
sysadmin user:shutdown
sysadmin user:halt
sysadmin user:mail
sysadmin user:operator
sysadmin user:games
5. 實例
1.統(tǒng)計/etc/fstab文件中每個單詞出現(xiàn)的次數(shù),并按從大到小排序
awk '{for(i=1;i<=NF;i++){words[$i]++}}END{for(key in words)print key,words[key]}' /etc/fstab|sort -k2 -nr
awk '{ips[$1]++}END{for(i in ips) print i,ips[i]}' access_nginx.log |column -t|sort -k2 -nr
2.統(tǒng)計/etc/fstab每個文件系統(tǒng)類型出現(xiàn)的次數(shù)
awk '!/^#/&&!/^$/{dev[$3]++}END{for(i in dev) print i,dev[i]}' /etc/fstab
3.ping一個域名,輸出ping此刻的時間
ping baidu.com|awk '{print $0" "strftime("%Y-%m-%d %H:%M:%S")}'
4.利用netstat監(jiān)控服務(wù)是否正常監(jiān)聽
netstat -lntup|awk 'NR>2{if($4 ~/.*:22/) print $0"yes";exit 0}'
5.統(tǒng)計web服務(wù)器日志狀態(tài)碼
awk '$9~"[0-9]"{stat[$9]++}END{for(i in stat) print i,stat[i]}' access_log
6. 注意事項
-
awk
同sed
命令類似,只不過sed
擅長取行,awk
命令擅長取列,awk是對文本進行格式化輸出,sed更傾向于對文件進行修改; -
對于讀入的文件可以根據(jù)自己需求對IFS/OFS對輸入和輸出進行修改;
-
awk非常的強大,但是也是三劍客中最難的一個,其作為一門單獨的語言,我們在Shell編程中學(xué)習(xí)常用的命令及語法就已經(jīng)足夠我們使用。
7. 小結(jié)
本章節(jié)我們系統(tǒng)性地學(xué)習(xí)了awk的語法結(jié)構(gòu)及處理模式,其相較于其他文本處理工具,更適合對文本進行格式化輸出,我們需要在合適的地方使用,其作為Linux系統(tǒng)上一個非常強大的文本格式輸出工具,也是一門語言,后期需要在實踐工作中更多地靈活運用,使得腳本編寫更加方便。