6. 數組:
因爲awk中數組的下標可以是數字和字母,數組的下標通常被稱爲關鍵字(key)。值和關鍵字都存儲在內部的一張針對key/value應用hash的表格裏。由於hash不是順序存儲,因此在顯示數組內容時會發現,它們並不是按照你預料的順序顯示出來的。數組和變量一樣,都是在使用時自動創建的,awk也同樣會自動判斷其存儲的是數字還是字符串。一般而言,awk中的數組用來從記錄中收集信息,可以用於計算總和、統計單詞以及跟蹤模板被匹配的次數等等。
/> cat employees
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
/> awk '{name[x++] = $2}; END{for (i = 0; i < NR; i++) print i, name[i]}' employees
0 Jones
1 Adams
2 Chang
3 Black
在上例中,數組name的下標是變量x。awk初始化該變量的值爲0,在每次使用後自增1,讀取文件中的第二個域的值被依次賦值給name數組的各個元素。在END模塊中,for循環遍歷數組的值。因爲下標是關鍵字,所以它不一定從0開始,可以從任何值開始。
#這裏是用內置變量NR作爲數組的下標了。
/> awk '{id[NR] = $3}; END {for (x = 1; x <= NR; x++) print id[x]}' employees
4424
5346
1654
1683
awk中還提供了一種special for的循環,見如下聲明:
for (item in arrayname) {
print arrayname[item]
}
/> cat db
Tom Jones
Mary Adams
Sally Chang
Billy Black
Tom Savage
Tom Chung
Reggie Steel
Tommy Tucker
/> awk '/^Tom/{name[NR]=$1}; END {for(i = 1;i <= NR; i++) print name[i]}' db
Tom
Tom
Tom
Tommy
從輸出結果可以看出,只有匹配正則表達式的記錄的第一個域被賦值給數組name的指定下標元素。因爲用NR作爲下標,所以數組的下標不可能是連續的,因此在END模塊中用傳統的for循環打印時,不存在的元素就打印空字符串了。下面我們看看用special for的方式會有什麼樣的輸出。
/> awk '/^Tom/{name[NR]=$1};END{for(i in name) print name[i]}' db
Tom
Tom
Tommy
Tom
下面我們看一下用字符串作爲下標的例子:(如果下標是字符串文字常量,則需要用雙引號括起來)
/> cat testfile2
tom
mary
sean
tom
mary
mary
bob
mary
alex
/> awk '/tom/{count["tom"]++}; /mary/{count["mary"]++}; END{print "There are " count["tom"] \
" Toms and " count["mary"] " Marys in the file."} testfile2
There are 2 Toms and 4 Marys in the file.
在上例中,count數組有兩個元素,下標分別爲tom和mary,每一個元素的初始值都是0,沒有tom被匹配的時候,count["tom"]就會加一,count["mary"]在匹配mary的時候也同樣如此。END模塊中打印出存儲在數組中的各個元素。
/> awk '{count[$1]++}; END{for(name in count) printf "%-5s%d\n",name, count[name]}' testfile2
mary 4
tom 2
alex 1
bob 1
sean 1
在上例中,awk是以記錄的域作爲數組count的下標。
/> awk '{count[$1]++; if (count[$1] > 1) name[$1]++}; END{print "The duplicates were "; for(i in name) print i}' testfile2
The duplicates were
mary
tom
在上例中,如count[$1]的元素值大於1的時候,也就是當名字出現多次的時候,一個新的數組name將被初始化,最後打印出那麼數組中重複出現的名字下標。
之前我們介紹的都是如何給數組添加新的元素,並賦予初值,現在我們需要介紹一下如何刪除數組中已經存在的元素。要完成這一功能我們需要使用內置函數delete,見如下命令:
/> awk '{count[$1]++}; \
END{for(name in count) {\
if (count[name] == 1)\
delete count[name];\
} \
for (name in count) \
print name}' testfile2
mary
tom
上例中的主要技巧來自END模塊,先是變量count數組,如果數組中某個元素的值等於1,則刪除該元素,這樣等同於刪除只出現一次的名字。最後用special for循環打印出數組中仍然存在的元素下標名稱。
最後我們來看一下如何使用命令行參數數組,見如下命令:
/> awk 'BEGIN {for(i = 0; i < ARGC; i++) printf("argv[%d] is %s.\n",i,ARGV[i]); printf("The number of arguments, ARGC=%d\n",ARGC)}' testfile "Peter Pan" 12
argv[0] is awk.
argv[1] is testfile.
argv[2] is Peter Pan.
argv[3] is 12.
The number of arguments, ARGC=4
從輸出結果可以看出,命令行參數數組ARGV是以0作爲起始下標的,命令行的第一個參數爲命令本身(awk),這個使用方式和C語句main函數完全一致。
/> awk 'BEGIN{name=ARGV[2]; print "ARGV[2] is " ARGV[2]}; $1 ~ name{print $0}' testfile2 "bob"
ARGV[2] is bob
bob
awk: (FILENAME=testfile2 FNR=9) fatal: cannot open file `bob' for reading (No such file or directory)
先解釋一下以上命令的含義,name變量被賦值爲命令行的第三個參數,即bob,之後再在輸入文件中找到匹配該變量值的記錄,並打印出該記錄。
在輸出的第二行報出了awk的處理錯誤信息,這主要是因爲awk將bob視爲輸入文件來處理了,然而事實上這個文件並不存在,下面我們需要做進一步的處理來修正這個問題。
/> awk 'BEGIN{name=ARGV[2]; print "ARGV[2] is " ARGV[2]; delete ARGV[2]}; $1 ~ name{print $0}' testfile2 "bob"
ARGV[2] is bob
bob
從輸出結果中我們可以看到我們得到了我們想要的結果。需要注意的是delete函數的調用必要要在BEGIN模塊中完成,因爲這時awk還沒有開始讀取命令行參數中指定的文件。
linux 命令詳解 十一
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
Linux基本操作命令
wbzjacky
2019-02-24 13:12:38
Linux核心技能与应用
wy53780
2020-04-23 14:02:05
Python與家國天下
豌豆花下貓
2019-02-24 22:22:40
linux上安裝Docker(非常簡單的安裝方法)
幸運券發放
2019-02-24 19:38:01
2019年Java面試-併發容器篇
王知無
2019-02-24 15:12:46
淺淡個人學習嵌入式Linux過程
wx5c317e5b736d2
2019-02-24 13:31:30
DHCP服務原理與搭建(Linux系統+路由器,二選一方案)
wx5c7174443c6f9
2019-02-24 13:23:18
Redis安裝與配置
劉遄
2019-02-24 13:12:51
如果同事暗中傷害你,應該怎麼辦?
這個饅頭有餡
2019-02-24 13:59:08
職場中,抱怨越多的員工,越被領導瞧不起!
這個饅頭有餡
2019-02-24 13:59:08
老程序員被裁,應屆生卻能月薪 1.3 萬?這你能忍?
前端高達
2019-02-24 13:48:04
遇到到處蹭吃卻從不請客吃飯的主怎麼辦?
樑軍年
2019-02-24 13:26:35
高標準機房綜合配線安裝
wbzjacky
2019-02-24 13:12:38