Linux三劍客之awk
awk是一個強大的文本分析工具,相對于grep的查找,sed的編輯,awk在其對資料分析并生成報告時,顯得尤為強大。簡單來說awk就是把檔案逐行的讀入,以空格為預設分隔符将每行切片,切開的部分再進行各種分析處理。它支援使用者自定義函數和動态正規表達式等先進功能,它在指令行中使用,但更多是作為腳本來使用。awk有很多内建的功能,比如數組、函數等
1、基本用法
1)直接使用awk指令調用,選項F用于指定域分隔符,預設為空格,格式如下:
awk [-F 分隔符] 'PATTERN {ACTION}' FILENAME...
2)先将要輸入的選項、模式和動作放入一個腳本檔案中,然後使用選項f調用:格式如下
awk -f SCRIPT FILENAME...
2、PATTERN
1)支援正規表達式
# 輸出/etc/passwd中以b或r開頭的行
[root@acer ~]# awk '/^[b,r]/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
2)支援表達式
# 輸出使用者uid小于10的使用者名及其uid
[root@acer ~]# awk -F: '$3<10{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
3)支援模式比對範圍(最小比對)從第一個pattern1開始到第一個pattern2結束
# 輸出root到halt之間的使用者
[root@acer ~]# awk -F: '/^root/,/^halt/{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
4)BEGIN/END在awk指令執行前/後執行一次
# 為2)中的輸出加上表頭“name、uid”,表尾“Screening is complete”
[root@acer ~]# awk -F: 'BEGIN{print "name uid"}''$3<10{print $1,$3}END{print "Screening is complete"}' /etc/passwd
name uid
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
Screening is complete
5)空模式:即對所有行執行ACTION操作
# 輸出所有使用者及其uid
[root@acer ~]# awk -F: '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
uucp 10
operator 11
games 12
gopher 13
ftp 14
nobody 99
dbus 81
vcsa 69
abrt 173
haldaemon 68
ntp 38
saslauth 499
postfix 89
sshd 74
tcpdump 72
tom 500
named 25
dhcpd 177
apache 48
mysql 27
建立一個文本文檔person.txt,内容如下:
1,zhangsan,teacher
2,lisi,CEO
3,wangwu,student
4,zhaoliu,CEO
5,huangquan,student
3、ACTION表示對比對到行的切片進行處理,常用的有
print:輸出,預設輸出分割符為空格
printf:格式化輸出,用法與C語言中printf一樣,格式一般為printf FORMAT,[ARGUMENT...],但是printf預設輸出後不換行,是以一般要與“\n”轉義字元連用
常用FORMAT及其說明
%c:作為一個ASCII碼字元輸出
%s:字元串
%o:八進制
%x:十六進制
%d:整數
%e:科學型輸出
%f:浮點型輸出
%%:顯示%
還可以使用修飾符來修飾輸出格式
N:顯示寬度
-:表示左對齊(預設右對齊)
# 格式化輸出person.txt中的内容
[root@acer ~]# awk -F, '{printf "%-3s%-10s%-10s\n",$1,$2,$3}' person.txt
1 zhangsan teacher
2 lisi CEO
3 wangwu student
4 zhaoliu CEO
5 huangquan student
4、内置變量
1)記錄變量
FS:指定輸入分隔符,相當于使用-F選項
OFS:指定輸出分隔符
RS:輸入文本資訊所使用的換行符,一般預設為空格即可
ORS:輸出文本資訊所使用的換行符,一般預設為空格即可
[root@acer ~]# awk 'BEGIN{FS=",";OFS=":"}{print $1,$2,$3}' person.txt
1:zhangsan:teacher
2:lisi:CEO
3:wangwu:student
4:zhaoliu:CEO
5:huangquan:student
2)資料變量
NR:awk指令處理的總行數
NF:目前處理行分割後的字段總數
FNR:awk指令處理的目前檔案的行數
# NR可以輸出awk需要處理的總行數
[root@acer ~]# awk -F, '{print NR}' person.txt
1
2
3
4
5
# NF可以輸出目前處理行分割後的字段總數,可以與$連用,表示輸出最後一個字段
[root@acer ~]# awk -F, '{print NF}' person.txt
3
3
3
3
3
[root@acer ~]# awk -F, '{print $NF}' person.txt
teacher
CEO
student
CEO
student
# NFR表示有多個檔案時awk指令處理目前檔案的行數
# 如:awk.txt檔案中有如下内容
[root@acer ~]# cat awk.txt
this,is,a,test.
# 則有
[root@acer ~]# awk '{print FNR}' person.txt awk.txt
1
2
3
4
5
1
3)使用者自定義變量
# 在BEGIN中定義變量
[root@acer ~]# awk 'BEGIN{test="hello awk";print test}'
hello awk
# 使用-v選項定義變量(但是這種用法好像必須要加BEGIN,是以個人感覺上一種會好一點)
[root@acer ~]# awk -v test="hello awk" 'BEGIN{print test}'
hello awk
5、進階用法
1)awk支援操作符
算術操作符、字元操作符、指派操作符、比較操作符、邏輯關系符、條件表達式及函數調用等
2)awk支援控制語句(與Java控制語句文法基本相同)
if-else
if(condition){statement;...}else {statement;...}
while
while(condition){statement;...}
do-while
do{statement;...}while(condition)
for
for(初始化;布爾表達式;更新) {statement;...}
for(聲明語句:表達式){statement;...}
case
switch(expression){case VALUE or /REGEXP/:statement;...default:statement;...}
break:提前結束循環
contuinue:進入下一輪循環
next:提前進入下一行文本處理
3)awk支援數組
可以自定義下标,如a[a]=a;a[b]=b;...
如果沒有定義下标,下标預設從1開始
如果要周遊數組中每個元素,則要使用for循環結構來周遊
for(聲明語句:表達式){statement;...}
# 統計并輸出/etc/passwd中不同bash的使用者個數
[root@acer ~]# awk -F: '{shell[$NF]++}END{for(A in shell){print A,shell[A]}}' /etc/passwd
/sbin/shutdown 1
/bin/csh 1
/bin/bash 2
/sbin/nologin 21
/sbin/halt 1
/bin/sync 1
# 上述指令中,shell是一個數組,而shell[$NF]分别可以表示為shell數組中以不同shell為下标的數組元素,統計之并用for循環結構依次輸出
# 統計并輸出person.txt中最後一個字段不同的使用者個數
[root@acer ~]# awk -F, '{job[$NF]++}END{for(I in job){print I,job[I]} }' person.txt
student 2
teacher 1
CEO 2
# 統計并輸出不同IP位址對目前web服務通路的次數
[root@acer ~]# awk '{ip[$1]++}END{for(I in ip){print I,ip[I]}}' /var/log/httpd/access_log