1. 程式人生 > >awk '!arr[$0]++'對文件進行處理

awk '!arr[$0]++'對文件進行處理

linux

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]++'對文件進行處理