很多人都知道awk '!a[$0]++' file可以去除文本中重復(fù)的行脆栋,但是對(duì)其到底是如何去重的卻不是很清楚饮笛,所以這里就單獨(dú)來(lái)分析一下這個(gè)命令懊悯。
首先我們要知道這條命令是隱含了一個(gè)print $0的凛捏,完整命令如下:
$ cat c
1
2
2
3
1
3
3
$ awk '!a[$0]++{print $0}' c
1
2
3
awk判定以下三種情況為“假”吞瞪,其他情況都為“真”:
數(shù)字0
空字符串""
未定義的變量箩朴,對(duì)于未定義的變量var岗喉,如果要進(jìn)行字符串操作,會(huì)被轉(zhuǎn)成空字符串""
炸庞,如果要進(jìn)行數(shù)學(xué)運(yùn)算钱床,會(huì)被轉(zhuǎn)成數(shù)字0
,也可以使用var""
來(lái)強(qiáng)制轉(zhuǎn)為空字符串""
埠居,var+0
來(lái)強(qiáng)制轉(zhuǎn)為數(shù)字0
所以上面這條awk語(yǔ)句的原理就是判斷!a[$0]++的值查牌,如果值為真就打印當(dāng)前行,值為假自然就不會(huì)打印當(dāng)前行了滥壕。
開(kāi)始分析!a[$0]++吧纸颜,不過(guò)還得先看一下awk中操作符的優(yōu)先級(jí)(由高到低排列):
$ #字段引用($1,$2)
++ --
^ ** #求冪
+ - ! #正、負(fù)绎橘、邏輯非
* / %
+ - #加法減法
(blank) #連接符
< <= == != > >=
~ !~
&&
||
?:
= += -= *= /= %= ^= **=
這里看到++操作符優(yōu)先級(jí)是高于!操作符的胁孙。
現(xiàn)在正式開(kāi)始分析!a[$0]++唠倦,先使用{print ">"a[$0]+0}來(lái)輸出每次進(jìn)行!a[$0]++計(jì)算后a[$0]的值:
$ echo -e "5\n5\n5"|awk '{print ">"a[$0]+0}!a[$0]++{print $0}'
>0
5
>1
>2
為了簡(jiǎn)化輸出,這里只對(duì)相同的三行進(jìn)行去重涮较,可以看到處理第一行之前a[$0]還是未定義的稠鼻,
所以輸出為空(這里通過(guò)a[$0]+0強(qiáng)制轉(zhuǎn)換成了0),當(dāng)?shù)谝恍刑幚硗瓿芍骯[$0]的值變成了1狂票,
第二行處理完成之后a[$0]的值變成了2候齿,以此類(lèi)推。
這里我們可以將a[$0]數(shù)組取值替換為一個(gè)簡(jiǎn)單的變量闺属,方便理解:
$ awk 'BEGIN{a=0;print !a++,a}'
1 1
$ awk 'BEGIN{a=1;print !a++,a}'
0 2
$ awk 'BEGIN{a=2;print !a++,a}'
0 3
我們知道a++操作符是在變量a使用完之后再對(duì)變量進(jìn)行自增慌盯,所以這里雖然++比!優(yōu)先級(jí)高,先跟變量a結(jié)合掂器,但是不會(huì)立即自增變量a的值润匙,而是在!a之后在自增變量a的值。通過(guò)例子來(lái)理解:
變量a的值為0唉匾,`!a`取反后返回1孕讳,然后`a++`將變量a的值自增1,此時(shí)`!a++`返回的值就是`!a`計(jì)算出來(lái)的1巍膘,同時(shí)變量a的值也變?yōu)榱?
變量a的值為1厂财,`!a`取反后返回0,然后`a++`將變量a的值自增1峡懈,此時(shí)`!a++`返回的值就是`!a`計(jì)算出來(lái)的0璃饱,同時(shí)變量a的值變?yōu)?
變量a的值為2,`!a`取反后返回0肪康,然后`a++`將變量a的值自增1荚恶,此時(shí)`!a++`返回的值就是`!a`計(jì)算出來(lái)的0,同時(shí)變量a的值變?yōu)?
現(xiàn)在是不是一目了然了磷支,再代入回之前的例子中:
$ echo -e "5\n5\n5"|awk '{print ">"a[$0]+0}!a[$0]++{print $0}'
>0
>1
>2
分析如下:
開(kāi)始處理第一行之前谒撼,
a[$0]
是未定義的,所以值為空(相當(dāng)于上面的a=0
)雾狈,!a[$0]
取反返回1廓潜,然后a[$0]++
將a[$0]
的值自增1,此時(shí)![$0]++
返回的值就是!a[$0]
計(jì)算出來(lái)的1善榛,數(shù)字1在awk中為真辩蛋,所以會(huì)執(zhí)行后面的{print $0}
輸出第一行,同時(shí)a[$0]
的值也變?yōu)榱?
開(kāi)始處理第二行之前移盆,a[$0]
值為1(相當(dāng)于上面的a=1
)悼院,!a[$0]
取反返回0,然后a[$0]++
將a[$0]
的值自增1咒循,此時(shí)![$0]++
返回的值就是!a[$0]
計(jì)算出來(lái)的0据途,數(shù)字0在awk中為假钮呀,所以不會(huì)執(zhí)行后面的{print $0}
來(lái)輸出第二行,同時(shí)a[$0]
的值變?yōu)?
開(kāi)始處理第三行之前昨凡,a[$0]
值為2(相當(dāng)于上面的a=2
)爽醋,!a[$0]
取反返回0,然后a[$0]++
將a[$0]
的值自增1便脊,此時(shí)![$0]++
返回的值就是!a[$0]
計(jì)算出來(lái)的0蚂四,數(shù)字0在awk中為假,所以不會(huì)執(zhí)行后面的{print $0}
來(lái)輸出第三行哪痰,同時(shí)a[$0]
的值變?yōu)?
分析完成遂赠,不過(guò)這只是我個(gè)人的理解,有不對(duì)的地方請(qǐng)回復(fù)指出晌杰,一起學(xué)習(xí)跷睦!