awk '!arr[$0]++'對文件進行處理
awk ‘!arr[$0]++‘後跟文件,可以過濾掉重復的行。
如下面的文件經過處理。
[[email protected] ~]# cat fstab # # /etc/fstab # /etc/fstab # /etc/fstab # /etc/fstab # /etc/fstab # Created by anaconda on Tue Jul 11 20:07:17 2017 # # Accessible filesystems, by reference, are maintained under ‘/dev/disk‘ # Accessible filesystems, by reference, are maintained under ‘/dev/disk‘ # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info # UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 / xfs defaults 0 0 UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 / xfs defaults 0 0 UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 / xfs defaults 0 0 UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 / xfs defaults 0 0 UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 / xfs defaults 0 0 UUID=a86604e8-9d34-4c3f-b3b3-fb3f3b72e356 /app xfs defaults 0 0 UUID=e45a1265-9826-442b-9ce6-5f44440e8d0e /boot xfs defaults 0 0 UUID=a86604e8-9d34-4c3f-b3b3-fb3f3b72e356 /app xfs defaults 0 0 UUID=e45a1265-9826-442b-9ce6-5f44440e8d0e /boot xfs defaults 0 0 UUID=f1eb3668-9539-4d4f-bae1-79f94029a101 swap swap defaults 0 0 UUID=645fd6f5-da6f-458e-968d-02c7106a3b62 /home xfs defaults,usrquota,grpquota 0 2 [[email protected] ~]# awk ‘!arr[$0]++‘ fstab # # /etc/fstab # Created by anaconda on Tue Jul 11 20:07:17 2017 # Accessible filesystems, by reference, are maintained under ‘/dev/disk‘ # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 / xfs defaults 0 0 UUID=a86604e8-9d34-4c3f-b3b3-fb3f3b72e356 /app xfs defaults 0 0 UUID=e45a1265-9826-442b-9ce6-5f44440e8d0e /boot xfs defaults 0 0 UUID=f1eb3668-9539-4d4f-bae1-79f94029a101 swap swap defaults 0 0 UUID=645fd6f5-da6f-458e-968d-02c7106a3b62 /home xfs defaults,usrquota,grpquota 0 2
我們知道,awk是一門語言。它的語言格式和bash差別還是有些的。awk得益於高效的執行速率,使用time命令查看執行時間,awk裏的循環遠甩bash幾條街。
awk ‘!arr[$0]++‘ a.txt會先執行!arr[$0],$0指整行,在此時把文件的整行當作關聯數組的下標的意思。關聯數組為下標為字符串的數組。awk和sed一樣,都是對文件進行行處理。每次抽取一行,處理,再抽取下一行處理。
#!是取反。
awk語言格式如下:
awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{action;… }‘ file ..
這裏的PATTERN是,根據pattern條件,過濾匹配的行,再做處理
(1)如果未指定:空模式,匹配每一行
(2) /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來
awk ‘/^UUID/{print $1}‘ /etc/fstab awk ‘!/^UUID/{print $1}‘ /etc/fstab
(3) relational expression: 關系表達式,結果為“真”才會被處理
真:結果為非0值,非空字符串
假:結果為空字符串或0值
(4) line ranges:行範圍 startline,endline:/pat1/,/pat2/ 不支持直接給出數字 格式
awk -F: ‘/^root\>/,/^nobody\>/{print $1}‘ /etc/passwd
awk -F: ‘(NR>=10&&NR<=20){print NR,$1}‘ /etc/passwd
(5) BEGIN/END模式 BEGIN{}: 僅在開始處理文件中的文本之前執行一次 END{}:僅在文本處理完成之後執行一次
awk ‘!arr[$0]++‘ a.txt這裏用到的是第三條。!arr$[0]++為這裏的關系表達式,但因為++的值是在對arr$[0]值取反後進行,這裏並不會影響輸入結果。
我們知道i++是先對i賦值,再++,++i則是先增加1,再把+1的值賦予i。
[[email protected] ~]# awk BEGIN‘{i=1;print i++}‘ 1 [[email protected] ~]# awk BEGIN‘{i=1;print ++i}‘ 2 [[email protected] ~]# awk BEGIN‘{a=0;print a++}‘ 0 [[email protected] ~]# awk BEGIN‘{a=0;print ++a}‘ 1
而當i值為0時,print i++依舊輸出0,結果為假。print ++i結果為1,即為真了。
awk對文本進行處理時,$0對應每行文本,即字符串,arr[$0]下面為字符串,是關聯數組。
而當變量被賦值為字符串時,變量對應的數值則為0。
[[email protected] ~]# awk BEGIN‘{a="shhkjl";print a}‘ shhkjl [[email protected] ~]# awk BEGIN‘{a="shhkjl";print !a}‘ 0 [[email protected] ~]# awk BEGIN‘{a="shhkjl";print a++}‘ 0 [[email protected] ~]# awk BEGIN‘{a="shhkjl";a++;print a}‘ 1
這樣,對其取反,值則為1。
awk如果不跟輸出條件,就默認輸出$0,即默認輸出本行的全部內容。
arr[$0]第一次讀取文件的第一行,因為文本內容被當作字符串處理,則arr[$0]一直為假,即arr[$0]=0,對arr[$0]取反則為真,即!arr[$0]=1,則會執行打印操作。
至於++,++的結果並不輸出,所以對當前行關系表達式的真假判斷不會造成影響,但++的結果會在對下一行進行處理時影響arr[$0]的結果,雖然下一行的arr[$0],又是另一個值了。
以上面fastb的處理為例。
awk首先抽取第一行,此時arr[$0]為arr[""],arr[""]的值為空字符串,即arr[""]=0,則有!arr[""]=1,打印本行。++是對arr[""]執行的操作。arr[""]原值為0,++後則為1。
也就是說!arr[$0]++,其實是兩個分開的並行動作,!arr[$0]是對關系表達式取反,arr[$0]++對arr[$0]進行+1的操作。!arr[$0]決定本行是否打印,arr[$0]的值則因為下標值的不同每次更換,如果遇不到相同行,則根本不會再起作用。
arr數組的第一個數為arr[""],在處理完第一行後,arr[""]被賦值為1。
對第二行處理時arr[$0]就成了arr["#"],arr["#"]="#",字符串,則arr["#"]=0,!arr["#"]=1,打印。
只要變量值為字符串,則變量值均為0。0為假,其他數值則均為真。
[[email protected] ~]# awk BEGIN‘{a=-1;print !a}‘ 0 [[email protected] ~]# awk BEGIN‘{a=10;print !a}‘ 0
直到遇到相同的行,如上面fstab文件中有重復的# /etc/fstab行,在對第一個# /etc/fstab行執行完操作後,arr["# /etc/fstab"]++後值為1。對第二個# /etc/fstab行進行處理時,arr[$0]即arr["# /etc/fstab"],由於數組中已有此元素,則不在重新賦值,arr["# /etc/fstab"]值為1,對其取反,!arr["# /etc/fstab"]=0,關系表達式為假,則本行不再打印。
然後,由於++,arr["# /etc/fstab"]的值則為2。
對第三個# /etc/fstab行進行處理,取反後依然為假,不輸出。
結果就是,awk ‘!arr[$0]++‘後跟文件,會把重復的行過濾掉,只打印非重復的行。
本文出自 “RightNow” 博客,請務必保留此出處http://amelie.blog.51cto.com/12850951/1967273
awk '!arr[$0]++'對文件進行處理