博客的開(kāi)頭我們說(shuō)過(guò),默認(rèn)情況下awk讀取文件的每行數(shù)據(jù)并將其存入$0變量當(dāng)中。其實(shí),awk在讀取數(shù)據(jù)之前會(huì)根據(jù)其內(nèi)部的預(yù)定義變量RS的值來(lái)分隔每條記錄(record)。RS的默認(rèn)值是“\n”,即換行符,因此也就會(huì)有我們剛才所說(shuō)的默認(rèn)情況。
所以,awk在讀取文件時(shí),會(huì)根據(jù)其自定義變量RS(Record Separator,記錄分隔符)的值將文件分為多條記錄來(lái)循環(huán)讀取,每讀取一條記錄就將其賦值給$0變量,賦值完畢后再執(zhí)行main代碼塊。
如果文件是一個(gè)空文件,那么就讀取不到記錄也就不會(huì)執(zhí)行main代碼塊。
[root@c7-server ~]# touch x.log
[root@c7-server ~]# awk '{print "hello world"}' x.log
[root@c7-server ~]#
可以在BEGIN代碼塊中設(shè)置RS的值來(lái)改變awk分隔記錄的方式。
[root@c7-server ~]# awk 'BEGIN{RS="com"}{print "---";print $0;print "---"}' a.txt
---
ID name gender age email phone
1 Bob male 28 abc@qq.
---
---
18023394012
2 Alice female 24 def@gmail.
---
... ...
被分隔的每條記錄中不會(huì)包含RS的值本身,在上述示例中即每條記錄不會(huì)包含com字符串。
細(xì)心的朋友會(huì)留意到
~]# awk '{print $0}' a.txt
當(dāng)我們不修改RS,上述指令在輸出的時(shí)候會(huì)使得每條記錄之間自動(dòng)換行,看起來(lái)就好像輸出數(shù)據(jù)包含了換行符(RS的默認(rèn)值)。這個(gè)特點(diǎn)留到我們講解另一個(gè)預(yù)定義變量ORS的時(shí)候再做解釋。
那么為什么一般將RS設(shè)置在BEGIN代碼塊當(dāng)中呢?
首先,一般來(lái)說(shuō)一個(gè)文件的RS在我們使用awk處理文件之前就可以確定了,而且一般不會(huì)改動(dòng)。其次,基于我們截止目前為止介紹的awk特性,如果我們?cè)趍ain代碼塊中設(shè)置RS的話,awk讀取第一條記錄的時(shí)候依然會(huì)使用換行符(RS的默認(rèn)值)來(lái)作為分隔符,讀取完第一條記錄接下來(lái)才是第一次進(jìn)入main代碼塊,然后才是設(shè)置RS的值,而且每次awk內(nèi)部循環(huán)執(zhí)行main時(shí)都要為RS賦相同值也沒(méi)有必要(性能略微損失)。
RS為單個(gè)字符時(shí)直接使用該字符作為分隔符;RS為多個(gè)字符時(shí)被awk識(shí)別為正則表達(dá)式。
如果記錄分隔符不存在于讀入數(shù)據(jù)中的話,那么我們便可以在一次內(nèi)部循環(huán)的情況下讀取出所有的數(shù)據(jù)。
RS="\0"和RS="^$":這兩種方式均可以一次性讀取所有數(shù)據(jù),區(qū)別在于部分文件可能包含\0字符。雖然在正則中^$表示空行,但是在文件中即使包含空行也不會(huì)將其作為RS。
[root@c7-server ~]# awk 'BEGIN{RS="\0"} {print "---";print $0;print "---"}' a.txt
---
ID name gender age email phone
... ...
10 Bruce female 27 bcbd@139.com 13942943905
---
[root@c7-server ~]# awk 'BEGIN{RS="^$"} {print "---";print $0;print "---"}' a.txt
---
ID name gender age email phone
... ...
10 Bruce female 27 bcbd@139.com 13942943905
---
RS="":按段落讀取。當(dāng)段落與段落之間均為空行的時(shí)候,按照段落作為分隔符。注意,空格和制表符雖然也是空白看不到的字符,但是不算空行而算空白符。網(wǎng)友們可以自行在a.txt中鍵入幾個(gè)空行查看效果。
~]# awk 'BEGIN{RS=""} {print "---";print $0;print "---"}' a.txt
RS="\n+":以至少一個(gè)換行符作為分隔符。默認(rèn)情況下每行數(shù)據(jù)都視為1條記錄,而該情況下可以將多個(gè)連續(xù)的換行符作為分隔符,使得空行不會(huì)被視為記錄。
當(dāng)我們使用正則作為分隔符的時(shí)候,分隔符可以有多種情況。每次awk遇到滿足正則條件的分隔符時(shí),都會(huì)將這次分隔符賦值給RT(Record Termination),我們可以通過(guò)查看該值來(lái)判斷到底這條記錄是以什么作為分隔符。
~]# awk 'BEGIN{RS="@[[:alnum:]]{1,5}.com"} {print "---"RT"---"}' a.txt
---@qq.com---
---@gmail.com---
---@163.com---
---@189.com---
---@xyz.com---
---@139.com---
---@189.com---
---@qq.com---
---@sohu.com---
---@139.com---
------
最后一個(gè)分隔符比較特殊。我猜測(cè)可能是因?yàn)橐呀?jīng)EOF了,就將EOF視為分隔符,雖然它并不滿足于正則條件。
在我們使用正則進(jìn)行匹配的時(shí)候如果想要忽略大小寫,可以使用預(yù)定義變量IGNORECASE。
~]# awk 'BEGIN{IGNORECASE=1} /alice|bob/{print $0}' a.txt
1 Bob male 28 abc@qq.com 18023394012
2 Alice female 24 def@gmail.com 18084925203
記錄號(hào)即“行號(hào)”,awk使用NF和FNR兩個(gè)預(yù)定義變量來(lái)保存記錄號(hào),每讀取1條記錄,它們的值就會(huì)加1。第一條記錄號(hào)的值就是1,以此開(kāi)始遞增。
~]# awk '{print NR,FNR}' a.txt a.txt
NR會(huì)一直遞增,即使數(shù)據(jù)的來(lái)源屬于不同的文件,而FNR在遇到新的文件的時(shí)候其值會(huì)重回1開(kāi)始遞增。
至此我們了解到,awk每讀取1條記錄就會(huì)設(shè)置$0、NR、FNR和RT的值。
awk讀取記錄以后,還會(huì)根據(jù)預(yù)定義變量FS(Field Separator,字段分隔符)將記錄劃分成多個(gè)字段。其值默認(rèn)是一個(gè)空格(FS=" "),表示將一個(gè)至多個(gè)空白字符(空格、制表符和換行符)識(shí)別為字段分隔符。將第一個(gè)字段賦值給$1,第二個(gè)字段賦值給$2,依次類推直至將最后一個(gè)字段賦值給$NF。預(yù)定義變量NF表示這條記錄的字段數(shù)量。大家可以自己試試。
awk '{print $1}' a.txt
awk '{print $6}' a.txt
awk '{print $NF}' a.txt
引用的字段如果超出最大字段數(shù)則反饋空字符串,如果是負(fù)數(shù)則報(bào)錯(cuò)。
[root@c7-server ~]# awk '{print $7}' a.txt
... ...
[root@c7-server ~]# awk '{print $-1}' a.txt
awk: cmd. line:1: (FILENAME=a.txt FNR=1) fatal: attempt to access field -1
通過(guò)預(yù)定義變量FS和選項(xiàng)-F可以用來(lái)指定字段分隔符。選項(xiàng)-F和預(yù)定義變量FS大同小異,只不過(guò)指定的位置不同罷了。
awk 'BEGIN{FS=":"}{print $1}' /etc/passwd awk -F ":" '{print $1}' /etc/passwd
字段分隔符的特性大多數(shù)在上面介紹FS時(shí)已經(jīng)介紹過(guò),補(bǔ)充幾點(diǎn)。
如果FS的值為空字符串"",那么會(huì)將記錄中的每個(gè)字符都識(shí)別為字段??崭褡址彩亲址?。
~]# echo "a c" | awk 'BEGIN{FS=""}{print $1;print $2;print $3}'
a
c
如果在記錄中無(wú)法找到字段分隔符則將整個(gè)記錄($0)賦值給第一個(gè)字段$1。
~]# awk 'BEGIN{FS="_"}{print $1;print $2}' a.txt
根據(jù)分隔符劃分字段的前提條件是文件有合適的分隔符便于我們劃分字段。我們copy一份a.txt至b.txt,并且修改某幾行的某幾個(gè)字段,使用等量的空格符來(lái)替換。
[root@c7-server ~]# cat b.txt
ID name gender age email phone
1 Bob male 28 abc@qq.com 18023394012
2 female 24 def@gmail.com 18084925203
3 Tony male 21 aaa@163.com 17048792503
4 Kevin 21 bbb@189.com 17023929033
5 Alex male 18 ccc@xyz.com 18185904230
6 Andy female ddd@139.com 18923902352
7 Jerry female 25 18785234906
8 Peter male 20 bax@qq.com 17729348758
9 Steven female 23 bc@sohu.com
10 Bruce female 27 bcbd@139.com 13942943905
此時(shí)再以字段分隔符的方式來(lái)為b.txt劃分字段就不合適了。
此時(shí)我們通過(guò)觀察發(fā)現(xiàn):
此時(shí)我們即可使用預(yù)定義變量FIELDFIDTHS來(lái)根據(jù)字段的字符寬度劃分字段。
~]# echo "abbcccddd" | awk 'BEGIN{FIELDWIDTHS="1 2 3 4"}{print $1;print $2;print $3;print $4}'
支持跳躍字符指定字段寬度。
~]# echo "a bb ccc ddd" | awk 'BEGIN{FIELDWIDTHS="1 1:2 2:3 3:4"}{print $1;print $2;print $3;print $4}'
支持通配符*匹配剩余所有字符。
~]# echo "abbcccddd" | awk 'BEGIN{FIELDWIDTHS="1 2 3 *"}{print $1;print $2;print $3;print $NF}' ~]# echo "a bb ccc ddd" | awk 'BEGIN{FIELDWIDTHS="1 1:2 2:3 3:*"}{print $1;print $2;print $3;print $NF}'
因此我們可以使用FIELDWIDTHS來(lái)處理b.txt了。注意觀察結(jié)果(結(jié)果沒(méi)有放入博文,請(qǐng)網(wǎng)友自行敲看看)。
~]# awk 'BEGIN{FIELDWIDTHS="2 2:6 2:6 2:3 2:13 2:*"} $1==2||$1==4||$1==6||$1==7||$1==9{print "----";print $1;print $2;print $3;print $4;print $5;print $6;print "----"}' b.txt
預(yù)定義變量FPAT的值是一個(gè)正則表達(dá)式,awk根據(jù)這個(gè)值去匹配$0,第一次匹配成功賦值給$1,以此類推直到匹配完整個(gè)$0。不會(huì)修改$0。
FPAT適用于當(dāng)我們打算使用分隔符取字段時(shí),字段值包含了分隔符的情況。例如如下csv文件。
~]# cat FPAT.csv
Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA
此時(shí)我們使用逗號(hào)作為分隔符取出的結(jié)果就不是我們想要的,因?yàn)榈谌齻€(gè)字段包含了分隔符。另外,這里我們使用了for循環(huán)遍歷了所有字段,第一次見(jiàn)此用法的網(wǎng)友照著敲直到功能即可,后面會(huì)講解for循環(huán)的。
~]# awk 'BEGIN{FS=","}{for(i=1;i<=NF;i++){print $i}}' FPAT.csv
Robbins
Arnold
"1234 A Pretty Street
NE"
MyTown
MyState
12345-6789
USA
這時(shí)可以采取FPAT。正則的第一部分指明“分隔符”逗號(hào)以外的多個(gè)字符識(shí)別為字段;正則的第二部分指明當(dāng)遇到兩個(gè)雙引號(hào)(在awk中需要使用轉(zhuǎn)義字符表示雙引號(hào)\")的時(shí)候,將其與其中包裹的任意字符識(shí)別為字段。這樣就可以正確分隔這個(gè)示例的字段了。
~]# awk 'BEGIN{FPAT="[^,]+|\".*\""}{for(i=1;i<=NF;i++){print $i}}' FPAT.csv
Robbins
Arnold
"1234 A Pretty Street, NE"
MyTown
MyState
12345-6789
USA
由于正則的貪婪匹配機(jī)制,如果記錄中包含2個(gè)以上的雙引號(hào)就會(huì)出問(wèn)題。
[root@c7-server ~]# cat FPAT.csv
Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,"12345-6789",USA
[root@c7-server ~]# awk 'BEGIN{FPAT="[^,]+|\".*\""}{for(i=1;i<=NF;i++){print $i}}' FPAT.csv
Robbins
Arnold
"1234 A Pretty Street, NE",MyTown,MyState,"12345-6789"
USA
結(jié)果并不是我們想要的,此時(shí)需要改寫正則。
~]# awk 'BEGIN{FPAT="[^,]+|\"[^\"]+\""}{for(i=1;i<=NF;i++){print $i}}' FPAT.csv
Robbins
Arnold
"1234 A Pretty Street, NE"
MyTown
MyState
"12345-6789"
USA
patsplit()函數(shù)的功能與FPAT預(yù)定義變量的功能相同。
至此我們學(xué)習(xí)了3種劃分字段的方式:
這三種方式只能選擇一種,它們相互之間是沖突的。
數(shù)組變量PROCINFO["FS"]存儲(chǔ)了字段分隔的三種方式,其值分別是FS、FIELDWIDTHS和FPAT。
~]# cat test.awk
BEGIN {
if(PROCINFO["FS"]=="FS"){
print "FS"
} else if(PROCINFO["FS"]=="FPAT") {
print "FPAT"
} else {
print "FIELDWIDTHS"
}
}
~]# awk -f test.awk
~]# awk -v FS=":" -f test.awk
~]# awk -v FIELDWIDTHS="3" -f test.awk
~]# awk -v FPAT="[[:alpha:]]+" -f test.awk
預(yù)定義變量FS的含義我們已經(jīng)很了解。有一個(gè)十分類似的預(yù)定義變量叫做OFS(Output FS),它表示當(dāng)$0(記錄)重新計(jì)算(可以理解為重建)的時(shí)候使用OFS的值作為輸出字段的分隔符。接下來(lái)我們來(lái)看幾個(gè)重新計(jì)算的情況。
1、當(dāng)修改$0的時(shí)候,將使用FS(假定我們就使用FS不使用其他劃分字段的方式)重新計(jì)算各個(gè)字段以及NF值。
awk 'BEGIN{FS=":"}{$0="a:b:c";print NF;for(i=1;i<=NF;i++){print $i}}' a.txt
2、當(dāng)修改具體的字段的時(shí)候,使用OFS重建記錄。注意,哪怕是自我賦值也屬于字段的修改。
awk 'BEGIN{OFS="-"}{$1=0;print $0}' a.txt
awk 'BEGIN{OFS="-"}{$1=$1;print $0}' a.txt
3、為不存在的字段賦值,將新增字段并為不存在的字段(若有)賦空字符串,使用OFS重建記錄。
awk 'BEGIN{OFS="-"}{$(NF+3)=5;print $0}' a.txt
4、增加NF,使用空字符串為新記錄賦值;減少NF,截?cái)喽嘤嘤涗?。均?huì)使用OFS重建記錄。
# awk 'BEGIN{OFS="-"}{NF+=3;print $0}' a.txt
# awk 'BEGIN{OFS="-"}{NF-=3;print $0}' a.txt
awk讀取記錄以后將數(shù)據(jù)原原本本存放于$0當(dāng)中,只要不會(huì)發(fā)生上述使用OFS重建記錄的事情,即便指定了OFS也無(wú)妨。
# awk 'BEGIN{OFS="-"}{print $0}' a.txt
OFS的默認(rèn)值是1個(gè)空格。因此即便沒(méi)指定具體的值也會(huì)使用單個(gè)空格重建記錄。
awk '{$1=$1;print $0}' a.txt
一般我們會(huì)先設(shè)置OFS的值再重建記錄。所以將其放入BEGIN中。如果先重建再設(shè)置OFS,那么第一行會(huì)按照默認(rèn)OFS重建,后續(xù)行才按照新OFS值重建。
awk '{$1=$1;OFS="-";print $0}' a.txt
awk '{$1=$1;OFS="-";$1=$1;print $0}' a.txt
awk 'BEGIN{OFS="-"}{$1=$1;print $0}' a.txt
awk '{$1=$1;print $0}' OFS="-" a.txt
這里如果看不懂的朋友,等后面學(xué)習(xí)了awk工作流程和變量以后就會(huì)明白awk執(zhí)行的順序了。
根據(jù)這個(gè)特性我們可以壓縮連續(xù)的多個(gè)空格。
# echo " a b c d " | awk '{$1=$1;print $0}'
# echo " a b c d " | awk 'BEGIN{OFS="-"}{$1=$1;print $0}'
1、根據(jù)行號(hào)(NR或者FNR)篩選記錄。
awk 'NR==2{print $0}' a.txt
awk 'NR>2{print}' a.txt
awk 'NR<2' a.txt
awk 'NR>=2' a.txt
awk 'NR<=2' a.txt
此前已經(jīng)說(shuō)過(guò),省略{action}即表示{print}等價(jià)于{print $0}。
2、根據(jù)正則表達(dá)式篩選記錄。
正則匹配,默認(rèn)使用$0來(lái)匹配,可以省略$0。
awk '/qq.com/' a.txt
awk '$0~/qq.com/' a.txt
匹配不包含@的記錄,即整條記錄均由非@字符構(gòu)成。
awk '/^[^@]+$/' a.txt
awk支持取反,使用取反更易理解。
awk '!/@/' a.txt
3、根據(jù)字段篩選記錄。
# awk '$4>24' a.txt
ID name gender age email phone
1 Bob male 28 abc@qq.com 18023394012
7 Jerry female 25 exdsa@189.com 18785234906
10 Bruce female 27 bcbd@139.com 13942943905
第一條記錄的$4是age,age是字符串,24是數(shù)字,其在進(jìn)行比較時(shí)會(huì)有內(nèi)部轉(zhuǎn)換機(jī)制,將24識(shí)別為字符串,字符串比較根據(jù)ASCII編碼(maybe)按字符一一比較,字符a大于字符2。如果我們期望不篩選出age那條,可以將其+0從而轉(zhuǎn)換成數(shù)字。字符串+0等于數(shù)字0。
# awk '($4+0)>24' a.txt
1 Bob male 28 abc@qq.com 18023394012
7 Jerry female 25 exdsa@189.com 18785234906
10 Bruce female 27 bcbd@139.com 13942943905
awk '$5~/qq.com/' a.txt
4、組合篩選。
使用邏輯與和邏輯或運(yùn)算符組合多個(gè)條件。
awk 'NR>=2&&NR<=4' a.txt
awk '($4+0)>=20||$3=="male"' a.txt
5、按照范圍篩選(flip-flop)。
awk 'NR==2,NR==4' a.txt
awk '$2=="Kevin",$5~/qq.com/' a.txt
字段的篩選即print $X(X表示具體的字段)沒(méi)什么好說(shuō)的,因此講字段的處理。
# awk 'NR>1{$4+=4;print $0}' a.txt
1 Bob male 32 abc@qq.com 18023394012
2 Alice female 28 def@gmail.com 18084925203
... ...
處理字段目前只接觸到賦值,修改了字段值會(huì)導(dǎo)致使用OFS重建$0。
要想使得輸出結(jié)果恢復(fù)重建前的效果,可以結(jié)合外部命令,例如該示例中的column。
# awk 'NR>1{$4+=4;print $0}' a.txt | column -t
1 Bob male 32 abc@qq.com 18023394012
2 Alice female 28 def@gmail.com 18084925203
... ...
或者在后續(xù)學(xué)會(huì)了字符串處理函數(shù)以后來(lái)實(shí)現(xiàn)?;舅悸肥侨〉?0重建前的$4的前后部分保留,然后修改$4的值,最后再將三部分組合。
awk 'NR>1{$6=$6"*";print $0}' a.txt
awk 'NR>1{$6=$6"*";print $0}' a.txt | column -t
該示例要求我們從ifconfig的輸出結(jié)果中取得ipv4地址(不包含環(huán)回地址lo),該示例同時(shí)也是常見(jiàn)的運(yùn)維面試題。
# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.152.100 netmask 255.255.255.0 broadcast 192.168.152.255
inet6 fe80::7a4:5a06:46b4:9ce5 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:46:79:46 txqueuelen 1000 (Ethernet)
RX packets 3151 bytes 258273 (252.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1606 bytes 166414 (162.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 72 bytes 8088 (7.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 72 bytes 8088 (7.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether 52:54:00:a6:3d:cf txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
有3種思路來(lái)取得地址。
思路一:ipv4地址位于包含“inet ”(注意有空格)的記錄,因此篩選出該記錄。同時(shí)我們要過(guò)濾掉換回地址,因此$2不以127打頭的記錄。將2個(gè)條件使用邏輯與連接。
# ifconfig | awk '/inet /&&!($2~/^127/)'
inet 192.168.152.100 netmask 255.255.255.0 broadcast 192.168.152.255
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
思路二:ifconfig輸出信息中包含了3段信息,每段表示1張網(wǎng)卡并以空行作為記錄分隔符。因此結(jié)合我們?cè)谥v解RS時(shí)提到的,這里我們以段劃分記錄。記錄不包含lo,同時(shí)我們?nèi)〉胕p地址所在的字段(手工數(shù)一下可知是第6字段)。
# ifconfig | awk 'BEGIN{RS=""}!/lo/{print $6}' 192.168.152.100 192.168.122.1
思路三:基于思路二,假設(shè)ip地址所在的字段數(shù)比較靠后,那么我們就需要數(shù)好幾個(gè)字段才可以數(shù)到ipv4地址,我們來(lái)看一下下面這個(gè)輸出結(jié)果。
# ifconfig | awk 'BEGIN{RS=""}!/lo/{print "---"$0"---"}'
---ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.152.100 netmask 255.255.255.0 broadcast 192.168.152.255
inet6 fe80::7a4:5a06:46b4:9ce5 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:46:79:46 txqueuelen 1000 (Ethernet)
RX packets 3997 bytes 330636 (322.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2063 bytes 225016 (219.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0---
---virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether 52:54:00:a6:3d:cf txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0---
按段劃分并篩選記錄以后,ipv4地址,從我們的視覺(jué)上來(lái)看,可以理解為每條記錄的第2“行”。不過(guò)我們這里因?yàn)橐呀?jīng)將整個(gè)網(wǎng)卡的信息(多行)理解為了1條記錄(行)了,因此我們要將原本的第二行識(shí)別為第2個(gè)字段,即修改FS的值。
# ifconfig | awk 'BEGIN{RS=""}!/lo/{FS="\n";print $2}'
flags=4163<UP,BROADCAST,RUNNING,MULTICAST>
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
輸出結(jié)果中第一行并不是我們所期望的字段信息。這是因?yàn)楦鶕?jù)RS=""讀取記錄以后會(huì)賦值$0,并按照FS的值(沒(méi)有另外指定因此使用FS=" ")賦值$1...$NF各個(gè)位置參數(shù)。賦值完畢以后才執(zhí)行main代碼塊賦值FS="\n",此時(shí)第一條記錄的各位置參數(shù)已經(jīng)確定好了。因此從第二條記錄開(kāi)始,$2才是我們所想要的信息。
我們只要將FS設(shè)置在BEGIN中即可,這也是為什么大多數(shù)情況下如果要修改默認(rèn)的FS和RS都在BEGIN中設(shè)置。
# ifconfig | awk 'BEGIN{RS="";FS="\n"}!/lo/{print $2}'
inet 192.168.152.100 netmask 255.255.255.0 broadcast 192.168.152.255
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
接下來(lái)我們將每條記錄的$2賦值給記錄$0本身,設(shè)置FS并取第2個(gè)字段的信息。按照下面的命令明顯無(wú)法取正確。
ifconfig | awk 'BEGIN{RS="";FS="\n"}!/lo/{$0=$2;FS=" ";print $2}'
# 第一條空信息
# 第二條空信息,注意這兩條空信息所取的字段是不同的。
原因此前我們也說(shuō)了,修改$0($0=$2)會(huì)重新劃分各字段,而FS=" "在修改$0之后出現(xiàn),因此第一條記錄依然是按照FS="\n"劃分字段。
【第一條空信息】的$0是:inet 192.168.152.100 netmask 255.255.255.0 broadcast 192.168.152.255,根據(jù)FS,因此它也會(huì)是$1,因此$2為空。
想讓【第一條空信息】取值正確的話,就要重新設(shè)置$0。
# ifconfig | awk 'BEGIN{RS="";FS="\n"}!/lo/{$0=$2;FS=" ";$0=$0;print $2}'
192.168.152.100
# 第二條空信息
【第二條空信息】取值錯(cuò)誤的原因是從第二條記錄開(kāi)始,F(xiàn)S的值就一直是main中的" ",我們需要在main的結(jié)尾再將其設(shè)置回BEGIN中的值。
# ifconfig | awk 'BEGIN{RS="";FS="\n"}!/lo/{$0=$2;FS=" ";$0=$0;print $2;FS="\n"}' 192.168.152.100 192.168.122.1
在我們實(shí)際使用當(dāng)中使用思路一和思路二取ipv4地址即可,思路三只是利于我們理解awk的工作原理,看不懂的同學(xué)多看看上面的【字段與記錄的重建】。
聯(lián)系客服