awk 数组用法【精华贴】
生活随笔
收集整理的這篇文章主要介紹了
awk 数组用法【精华贴】
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
文本處理的工作中,awk的數(shù)組是必不可少的工具,在這里,同樣以總結(jié)經(jīng)驗(yàn)和教訓(xùn)的方式和大家分享下我的一些學(xué)習(xí)心得,如有錯(cuò)誤的地方,請大家指正和補(bǔ)充。
awk的數(shù)組,一種關(guān)聯(lián)數(shù)組(Associative Arrays),下標(biāo)可以是數(shù)字和字符串。因無需對數(shù)組名和元素提前聲明,也無需指定元素個(gè)數(shù) ,所以awk的數(shù)組使用非常靈活。
首先介紹下幾個(gè)awk數(shù)組相關(guān)的知識(shí)點(diǎn):
<1>建立數(shù)組 array[index] = value :數(shù)組名array,下標(biāo)index以及相應(yīng)的值value。 復(fù)制代碼
<2>讀取數(shù)組值
{ for (item in array)??print array[item]} # 輸出的順序是隨機(jī)的
{for(i=1;i<=len;i++)??print array[i]} # Len 是數(shù)組的長度 復(fù)制代碼
<3>多維數(shù)組,array[index1,index2,……]:SUBSEP是數(shù)組下標(biāo)分割符,默認(rèn)為“\034”。可以事先設(shè)定SUBSEP,也可以直接在SUBSEP的位置輸入你要用的分隔符,如:
awk 'BEGIN{SUBSEP=":";array["a","b"]=1;for(i in array) print i}'
a:b
awk 'BEGIN{array["a"":""b"]=1;for(i in array) print i}'
a:b 復(fù)制代碼
但,有些特殊情況需要避免,如:
awk 'BEGIN{
SUBSEP=":"
array["a","b:c"]=1? ?? ?? ?? ?? ?# 下標(biāo)為“a:b:c”
array["a:b","c"]=2? ?? ?? ?? ?? ?#下標(biāo)同樣是“a:b:c”
for (i in array) print i,array[i]}'
a:b:c 2? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?#所以數(shù)組元素只有一個(gè)。 復(fù)制代碼
<4>刪除數(shù)組或數(shù)組元素: 使用delete 函數(shù)
delete array? ?? ?? ?? ?? ?? ?? ?#刪除整個(gè)數(shù)組
delete array[item]? ?? ?? ???# 刪除某個(gè)數(shù)組元素(item) 復(fù)制代碼
<5> 排序:awk中的asort函數(shù)可以實(shí)現(xiàn)對數(shù)組的值進(jìn)行排序,不過排序之后的數(shù)組下標(biāo)改為從1到數(shù)組的長度。在gawk 3.1.2以后的版本還提供了一個(gè)asorti函數(shù),這個(gè)函數(shù)不是依據(jù)關(guān)聯(lián)數(shù)組的值,而是依據(jù)關(guān)聯(lián)數(shù)組的下標(biāo)排序,即asorti(array)以后,仍會(huì)用數(shù)字(1到數(shù)組長度)來作為下標(biāo),但是array的數(shù)組值變?yōu)榕判蚝蟮脑瓉淼南聵?biāo),除非你指定另一個(gè)參數(shù)如:asorti(a,b)。(非常感謝lionfun對asorti的指正和補(bǔ)充
)
echo 'aa
bb
aa
bb
cc' |\
awk '{a[$0]++}END{l=asorti(a);for(i=1;i<=l;i++)print a[i]}'
aa
bb
cc
echo 'aa
bb
aa
bb
cc' |\
awk '{a[$0]++}END{l=asorti(a,b);for(i=1;i<=l;i++)print b[i],a[b[i]]}'
aa 2
bb 2
cc 1 復(fù)制代碼
下面說awk數(shù)組的實(shí)際應(yīng)用。
1.??除去重復(fù)項(xiàng), 這個(gè)不多說, 只給出代碼: awk '!a[$0]++' file(s)? ?? ?? ?? ?? ?? ??
awk '!($0 in a){a[$0];print}' file(s)? ? 復(fù)制代碼
另一種:
http://bbs.chinaunix.net/thread-1859344-1-1.html
?
2. 計(jì)算總數(shù)(sum),如: awk??'{name[$0]+=$1};END{for(i in name) print??i, name[i]}'
再舉個(gè)例子:
echo "aaa 1
aaa 1
ccc 1
aaa 1
bbb 1
ccc 1" |awk '{a[$1]+=$2}END{for(i in a) print i,a[i]}'
aaa 3
bbb 1
ccc 2 復(fù)制代碼
3. 查看文件差異。
cat file1
aaa
bbb
ccc
ddd
cat file2
aaa
eee
ddd
fff 復(fù)制代碼
<1>??合并file1和file2,除去重復(fù)項(xiàng):
awk 'NR==FNR{a[$0]=1;print}? ?#讀取file1,建立數(shù)組a,下標(biāo)為$0,并賦值為1,然后打印
NR>FNR{? ?? ?? ?? ?? ?? ? #讀取file2
if(!(a[$0])) {print }? ?? ?#如果file2 的$0不存在于數(shù)組a中,即不存在于file1,則打印。
}' file1 file2
aaa
bbb
ccc
ddd
eee
fff 復(fù)制代碼
<2> 提取文件1中有,但文件2中沒有:
awk 'NR==FNR{a[$0]=1}? ?? ?? ???#讀取file2,建立數(shù)組a,下標(biāo)為$0,并賦值為1
NR>FNR{? ?? ?? ?? ?? ?? ? #讀取file1
if(!(a[$0])) {print }? ?? ?#如果file1 的$0不存在于數(shù)組a中,即不存在于file2,則打印。
}' file2 file1
bbb
ccc 復(fù)制代碼
另:
http://bbs.chinaunix.net/viewthr ... &page=1#pid15547885
?
4.??排序: echo "a
1
0
b
2
10
8
100" |
awk '{a[$0]=$0} #建立數(shù)組a,下標(biāo)為$0,賦值也為$0
END{
len=asort(a)? ?? ?#利用asort函數(shù)對數(shù)組a的值排序,同時(shí)獲得數(shù)組長度len
for(i=1;i<=len;i++) print i "\t"a[i]??#打印
}'
1? ?? ? 0
2? ?? ? 1
3? ?? ? 2
4? ?? ? 8
5? ?? ? 10
6? ?? ? 100
7? ?? ? a
8? ?? ? b 復(fù)制代碼
5.??有序輸出:采用(index in array)的方式打印數(shù)組值的順序是隨機(jī)的,如果要按原序輸出,則可以使用下面的方法:
http://bbs2.chinaunix.net/viewthread.php?tid=1811279
awk '{a[$1]=$2
c[j++]=$1}
END{
for(m=0;m<j;m++)print c[m],a[c[m]]
}' 復(fù)制代碼
6.??多個(gè)文本編輯:這里主要指的是待處理的文本之間的格式上有區(qū)別,如分隔符不同,;或是待處理文本需提取的信息的位置不同,如不同的列或行。
<例1>: cat file1
g1.1 2
g2.2 4
g2.1 5
g4.1 3
cat file2
g1.1 2
g1.2 3
g4.1 4
cat file3
g1.2 3
g5.1 3 復(fù)制代碼
要求輸出:
g1.1 2 2 -
g1.2 - 3 3
g2.2 4 - -
g2.1 5 - -
g4.1 3 4 -
g5.1 - - 3 復(fù)制代碼
實(shí)現(xiàn)代碼如下:
awk '{a[ARGIND" "$1]=$2 # ARGIND是當(dāng)前命令行文件的位置(從0開始),將它和第一列的value作為下標(biāo),建立數(shù)組a。
? ?? ? b[$1]? ?#將第一列的value作為下標(biāo),建立數(shù)組b,目的是在讀完所有文件之后,能得到第一列value的uniqe-list。
? ?? ???}
END{?
? ?? ???for(i in b) {?
? ?? ?? ?? ?? ? printf i" "?
? ?? ?? ?? ?? ? for(j=1;j<=ARGIND;j++) printf "%s ", a[j" "i]?a[j" "i]:"-" #此時(shí)的ARGIND值為3.
print ""?
? ?? ?? ?? ?? ? }
? ?? ???}' file1 file2 file3 復(fù)制代碼
這里是利用awk的內(nèi)置變量ARGIND來處理完成對文件的處理。關(guān)于ARGIND,ARGV,ARGC的使用,大家可以參考:
http://bbs.chinaunix.net/viewthr ... 0335&from=favorites
。
當(dāng)然,我們也可以利用另外一個(gè)內(nèi)置變量FILENAME來完成相同的任務(wù)(大家可以先想想怎么寫),如下: awk '{a[FILENAME" "$1]=$2;b[$1];c[FILENAME]}END{for(i in b) {printf i" ";for(j in c) printf "%s ", a[j" "i]?a[j" "i]:"-";print""}}' file1 file2 file3 復(fù)制代碼
<例2>:對上面的數(shù)據(jù)的格式稍作改動(dòng),每個(gè)文件的分隔符都一樣的情況,但輸出要求不變:
cat file1
g1.1|2
g2.2|4
g2.1|5
g4.1|3
cat file2
g1.1#2
g1.2#3
g4.1#4
cat file3
g1.2@3
g5.1@3 復(fù)制代碼
實(shí)現(xiàn)代碼如下:
awk '{a[ARGIND" "$1]=$2
b[$1]
}
END{
for(i in b) {
printf i" "
for(j=2;j<=ARGIND;j+=2) printf "%s ", a[j" "i]?a[j" "i]:"-" # 由于FS的設(shè)置也是有對應(yīng)ARGIND值,所以對ARGIND稍作改動(dòng)。
print ""
}
}' FS="|" file1 FS="#" file2 FS="@" file3 # 對每個(gè)文件分別設(shè)置FS的值。 復(fù)制代碼
因?yàn)檫@個(gè)例子的數(shù)據(jù)比較簡單,我們也可以在BEGIN模塊中完成對FS值設(shè)置,如下:
awk 'BEGIN{FS="[|#@]"}{a[ARGIND" "$1]=$2; b[$1]}END{for(i in b) {printf i" ";for(j=1;j<=ARGIND;j++) printf "%s ", a[j" "i]?a[j" "i]:"-"; print ""}}' file1 file2 file3 復(fù)制代碼
利用FILENAME 同樣可以解決問題:
awk '
FILENAME=="file1"{FS="|"}? ? # 設(shè)置FS
FILENAME=="file2"{FS="#"}? ?#設(shè)置FS
FILENAME=="file3"{FS="@"}??#設(shè)置FS?
# 稍顯繁瑣,不過一目了然
{$0=$0}? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???#使FS生效。
{a[ARGIND" "$1]=$2; b[$1]}
END{ for(i in b) {printf i" "; for(j=1;j<=ARGIND;j++) printf "%s ", a[j" "i]?a[j" "i]:"-"; print ""}
}' file1 file2 file3 復(fù)制代碼
推薦一個(gè)關(guān)于數(shù)組處理文件的帖子
http://www.chinaunix.net/jh/24/577044.html
?,里面有不少例子供大家學(xué)習(xí)。
7.??文本翻轉(zhuǎn)或移位:二維或多維數(shù)組的應(yīng)用
<例1>: Inputfile
1 2 3 4 5 6
2 3 4 5 6 1
3 4 5 6 1 2
4 5 6 1 2 3
Outputfile
4 3 2 1
5 4 3 2
6 5 4 3
1 6 5 4
2 1 6 5
3 2 1 6
awk '{
? ???if (max_nf < NF)
? ?? ?? ? max_nf = NF # 數(shù)組第一維的長度
? ???max_nr = NR? ?? ?# 數(shù)組第二維的長度
? ???for (x = 1; x <= NF; x++)
? ?? ?? ? vector[x, NR] = $x #建立數(shù)組vector
}
END {
? ???for (x = 1; x <= max_nf; x++) {
? ?? ?? ? for (y = max_nr; y >= 1; --y)
? ?? ?? ?? ?? ?printf("%s ", vector[x, y])
? ?? ?? ? printf("\n")
? ???}
}' 復(fù)制代碼
<例2>:來自
http://bbs.chinaunix.net/viewthr ... &page=1#pid13339226
有兩個(gè)文本a和b,要求輸出c文本,合并的規(guī)則是按照第一行的headline(按字母順序)合并文本a和b,空缺按“0”補(bǔ)齊。 cat a.txt
a b c d
1 2 9 7
4 5 8 9
5 3 6 1
cat b.txt
a e f d g
9 2 4 7 3
4 3 7 9 4
cat c.txt
a b c d e f g
1 2 9 7 0 0 0
4 5 8 9 0 0 0
5 3 6 1 0 0 0
9 0 0 7 2 4 3
4 0 0 9 3 7 4 復(fù)制代碼
下面我們來參看并解讀下Tim大師的代碼:
awk '
FNR==1{? ? #FNR==1,即a和b文本的第一行,這個(gè)用的真的很巧妙。
? ?? ???for(i=1;i<=NF;i++){?
? ?? ?? ?? ?? ? b[i]=$i? ? #讀取文本的每個(gè)元素存入數(shù)組b
? ?? ?? ?? ?? ? c[$i]++}??#另建立數(shù)組c,并統(tǒng)計(jì)每個(gè)元素的個(gè)數(shù)
? ?? ?? ?? ?? ? next? ?? ?? ? #可以理解為,讀取FNR!=1的文本內(nèi)容。
? ?? ???}
{k++? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? # 統(tǒng)計(jì)除去第一行的文本行數(shù)
for(i=1;i<=NF;i++)a[k","b[i]]=$i??#利用一個(gè)二維數(shù)組來保持每個(gè)數(shù)字的位置, k,b[i]可以理解為每個(gè)數(shù)字的坐標(biāo)。
}
END{
? ?? ???l=asorti(c)? ?? ?? ? #利用asorti函數(shù)對數(shù)組的下標(biāo)進(jìn)行排序,并獲取數(shù)組長度,即輸出文件的列數(shù)(NF值)
? ?? ???for(i=1;i<=l;i++)printf c[i]" " # 先打印第一行,相當(dāng)于headline。
? ?? ???print ""
? ?? ???for(i=1;i<=k;i++){
? ?? ?? ?? ?? ? for(j=1;j<=l;j++)printf a[i","c[j]]?a[i","c[j]]" ":"0 " # 打印二維數(shù)組的值。
? ?? ?? ?? ?? ? print ""}
? ?? ???}' a.txt b.txt 復(fù)制代碼
8.??選擇性打印:
打印某個(gè)關(guān)鍵字前幾行,以3行為例: seq 20 |awk '/\<10\>/{for(i=NR-3;i<NR;i++)print a[i%3];exit}{a[NR%3]=$0}'
7
8
9 復(fù)制代碼
利用NR取余數(shù),建立數(shù)組,這是一種非常高效的代碼。
9. 通過split函數(shù)建立數(shù)組:數(shù)組的下標(biāo)為從1開始的數(shù)字。 split(s, a [, r]) # s:string, a:array name,[,r]:regular expression。
echo 'abcd' |awk '{len=split($0,a,"");for(i=1;i<=len;i++) print "a["i"] = " a[i];print "length = " len}'
a[1] = a
a[2] = b
a[3] = c
a[4] = d
length = 4 復(fù)制代碼
10. awk數(shù)組使用的小技巧和需要避免的用法:
<1> 嵌套數(shù)組: awk 'BEGIN{a[1]=3;b[1]=1;print a[b[1]]}'
3 復(fù)制代碼
<2> 下標(biāo)設(shè)為變量或函數(shù):
awk 'BEGIN{s=123;a[substr(s,2)]=substr(s,1,1);for(i in a)print "index : "i"\nvalue : "a[i]}'
index : 23
value : 1 復(fù)制代碼
<3> 不可以將數(shù)組名作為變量使用,否則會(huì)報(bào)錯(cuò):
awk 'BEGIN{a["1"] = 3; delete a;a=3;print a}'??#即使你已經(jīng)使用了delete函數(shù)。
awk: fatal: attempt to use array `a' in a scalar context 復(fù)制代碼
<4> 數(shù)組的長度:
length(array)?? 復(fù)制代碼
<5> match 函數(shù)也可以建立數(shù)組(你知道么?
,版本要求高于gawk 3.1.2)
echo "foooobazbarrrrr |?
gawk '{ match($0, /(fo+).+(bar*)/, arr)??#匹配到的部分自動(dòng)賦值到arr中,下標(biāo)從1開始
? ?? ?? ? print arr[1], arr[2]
? ?? ?? ? print arr[1, "start"], arr[1, "length"]??#二維數(shù)組arr[index,"start"]值=RSTART
? ?? ?? ? print arr[2, "start"], arr[2, "length"]??#二維數(shù)組arr[index,"length"]值=RLENGTH
? ?? ?? ? }'
foooo barrrrr
1 5
9 7 復(fù)制代碼
<6>想到過用split清空數(shù)組么?
awk 'BEGIN{
split("abc",array,"")
print "array[1] = "array[1],"\narray[2] = "array[2],"\narray[3] = "array[3]
split("",array)
print "array[1] = "array[1],"\narray[2] ="array[2],"\narray[3] ="array[3]
}'
array[1] = a
array[2] = b
array[3] = c
array[1] =
array[2] =
array[3] = 復(fù)制代碼
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
awk的數(shù)組,一種關(guān)聯(lián)數(shù)組(Associative Arrays),下標(biāo)可以是數(shù)字和字符串。因無需對數(shù)組名和元素提前聲明,也無需指定元素個(gè)數(shù) ,所以awk的數(shù)組使用非常靈活。
首先介紹下幾個(gè)awk數(shù)組相關(guān)的知識(shí)點(diǎn):
<1>建立數(shù)組
下面說awk數(shù)組的實(shí)際應(yīng)用。
1.??除去重復(fù)項(xiàng), 這個(gè)不多說, 只給出代碼:
2. 計(jì)算總數(shù)(sum),如:
4.??排序:
<例1>:
當(dāng)然,我們也可以利用另外一個(gè)內(nèi)置變量FILENAME來完成相同的任務(wù)(大家可以先想想怎么寫),如下:
7.??文本翻轉(zhuǎn)或移位:二維或多維數(shù)組的應(yīng)用
<例1>:
有兩個(gè)文本a和b,要求輸出c文本,合并的規(guī)則是按照第一行的headline(按字母順序)合并文本a和b,空缺按“0”補(bǔ)齊。
打印某個(gè)關(guān)鍵字前幾行,以3行為例:
9. 通過split函數(shù)建立數(shù)組:數(shù)組的下標(biāo)為從1開始的數(shù)字。
<1> 嵌套數(shù)組:
總結(jié)
以上是生活随笔為你收集整理的awk 数组用法【精华贴】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。