日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

awk 数组用法【精华贴】

發布時間:2025/4/14 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 awk 数组用法【精华贴】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文本處理的工作中,awk的數組是必不可少的工具,在這里,同樣以總結經驗和教訓的方式和大家分享下我的一些學習心得,如有錯誤的地方,請大家指正和補充。

awk的數組,一種關聯數組(Associative Arrays),下標可以是數字和字符串。因無需對數組名和元素提前聲明,也無需指定元素個數 ,所以awk的數組使用非常靈活。
首先介紹下幾個awk數組相關的知識點:

<1>建立數組
  • array[index] = value :數組名array,下標index以及相應的值value。
  • 復制代碼 <2>讀取數組值
  • { for (item in array)??print array[item]} # 輸出的順序是隨機的
  • {for(i=1;i<=len;i++)??print array[i]} # Len 是數組的長度
  • 復制代碼 <3>多維數組,array[index1,index2,……]:SUBSEP是數組下標分割符,默認為“\034”。可以事先設定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
  • 復制代碼 但,有些特殊情況需要避免,如:
  • awk 'BEGIN{
  • SUBSEP=":"
  • array["a","b:c"]=1? ?? ?? ?? ?? ?# 下標為“a:b:c”
  • array["a:b","c"]=2? ?? ?? ?? ?? ?#下標同樣是“a:b:c”
  • for (i in array) print i,array[i]}'
  • a:b:c 2? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?#所以數組元素只有一個。
  • 復制代碼 <4>刪除數組或數組元素: 使用delete 函數
  • delete array? ?? ?? ?? ?? ?? ?? ?#刪除整個數組
  • delete array[item]? ?? ?? ???# 刪除某個數組元素(item)
  • 復制代碼 <5> 排序:awk中的asort函數可以實現對數組的值進行排序,不過排序之后的數組下標改為從1到數組的長度。在gawk 3.1.2以后的版本還提供了一個asorti函數,這個函數不是依據關聯數組的值,而是依據關聯數組的下標排序,即asorti(array)以后,仍會用數字(1到數組長度)來作為下標,但是array的數組值變為排序后的原來的下標,除非你指定另一個參數如:asorti(a,b)。(非常感謝lionfun對asorti的指正和補充

  • 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
  • 復制代碼

    下面說awk數組的實際應用。

    1.??除去重復項, 這個不多說, 只給出代碼:
  • awk '!a[$0]++' file(s)? ?? ?? ?? ?? ?? ??
  • awk '!($0 in a){a[$0];print}' file(s)? ?
  • 復制代碼 另一種: http://bbs.chinaunix.net/thread-1859344-1-1.html ?

    2. 計算總數(sum),如:
  • awk??'{name[$0]+=$1};END{for(i in name) print??i, name[i]}'

  • 再舉個例子:

  • 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
  • 復制代碼 3. 查看文件差異。
  • cat file1
  • aaa
  • bbb
  • ccc
  • ddd
  • cat file2
  • aaa
  • eee
  • ddd
  • fff
  • 復制代碼 <1>??合并file1和file2,除去重復項:
  • awk 'NR==FNR{a[$0]=1;print}? ?#讀取file1,建立數組a,下標為$0,并賦值為1,然后打印
  • NR>FNR{? ?? ?? ?? ?? ?? ? #讀取file2
  • if(!(a[$0])) {print }? ?? ?#如果file2 的$0不存在于數組a中,即不存在于file1,則打印。
  • }' file1 file2
  • aaa
  • bbb
  • ccc
  • ddd
  • eee
  • fff
  • 復制代碼 <2> 提取文件1中有,但文件2中沒有:
  • awk 'NR==FNR{a[$0]=1}? ?? ?? ???#讀取file2,建立數組a,下標為$0,并賦值為1
  • NR>FNR{? ?? ?? ?? ?? ?? ? #讀取file1
  • if(!(a[$0])) {print }? ?? ?#如果file1 的$0不存在于數組a中,即不存在于file2,則打印。
  • }' file2 file1
  • bbb
  • ccc
  • 復制代碼 另: http://bbs.chinaunix.net/viewthr ... &page=1#pid15547885 ?

    4.??排序:
  • echo "a
  • 1
  • 0
  • b
  • 2
  • 10
  • 8
  • 100" |
  • awk '{a[$0]=$0} #建立數組a,下標為$0,賦值也為$0
  • END{
  • len=asort(a)? ?? ?#利用asort函數對數組a的值排序,同時獲得數組長度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
  • 復制代碼 5.??有序輸出:采用(index in array)的方式打印數組值的順序是隨機的,如果要按原序輸出,則可以使用下面的方法: 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]]
  • }'
  • 復制代碼 6.??多個文本編輯:這里主要指的是待處理的文本之間的格式上有區別,如分隔符不同,;或是待處理文本需提取的信息的位置不同,如不同的列或行。
    <例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
  • 復制代碼 要求輸出:
  • g1.1 2 2 -
  • g1.2 - 3 3
  • g2.2 4 - -
  • g2.1 5 - -
  • g4.1 3 4 -
  • g5.1 - - 3
  • 復制代碼 實現代碼如下:
  • awk '{a[ARGIND" "$1]=$2 # ARGIND是當前命令行文件的位置(從0開始),將它和第一列的value作為下標,建立數組a。
  • ? ?? ? b[$1]? ?#將第一列的value作為下標,建立數組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]:"-" #此時的ARGIND值為3.
  • print ""?
  • ? ?? ?? ?? ?? ? }
  • ? ?? ???}' file1 file2 file3
  • 復制代碼 這里是利用awk的內置變量ARGIND來處理完成對文件的處理。關于ARGIND,ARGV,ARGC的使用,大家可以參考: http://bbs.chinaunix.net/viewthr ... 0335&from=favorites
    當然,我們也可以利用另外一個內置變量FILENAME來完成相同的任務(大家可以先想想怎么寫),如下:
  • 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
  • 復制代碼 <例2>:對上面的數據的格式稍作改動,每個文件的分隔符都一樣的情況,但輸出要求不變:
  • 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
  • 復制代碼 實現代碼如下:
  • 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的設置也是有對應ARGIND值,所以對ARGIND稍作改動。
  • print ""
  • }
  • }' FS="|" file1 FS="#" file2 FS="@" file3 # 對每個文件分別設置FS的值。
  • 復制代碼 因為這個例子的數據比較簡單,我們也可以在BEGIN模塊中完成對FS值設置,如下:
  • 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
  • 復制代碼 利用FILENAME 同樣可以解決問題:
  • awk '
  • FILENAME=="file1"{FS="|"}? ? # 設置FS
  • FILENAME=="file2"{FS="#"}? ?#設置FS
  • FILENAME=="file3"{FS="@"}??#設置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
  • 復制代碼 推薦一個關于數組處理文件的帖子 http://www.chinaunix.net/jh/24/577044.html ?,里面有不少例子供大家學習。

    7.??文本翻轉或移位:二維或多維數組的應用
    <例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 # 數組第一維的長度
  • ? ???max_nr = NR? ?? ?# 數組第二維的長度
  • ? ???for (x = 1; x <= NF; x++)
  • ? ?? ?? ? vector[x, NR] = $x #建立數組vector
  • }
  • END {
  • ? ???for (x = 1; x <= max_nf; x++) {
  • ? ?? ?? ? for (y = max_nr; y >= 1; --y)
  • ? ?? ?? ?? ?? ?printf("%s ", vector[x, y])
  • ? ?? ?? ? printf("\n")
  • ? ???}
  • }'
  • 復制代碼 <例2>:來自 http://bbs.chinaunix.net/viewthr ... &page=1#pid13339226
    有兩個文本a和b,要求輸出c文本,合并的規則是按照第一行的headline(按字母順序)合并文本a和b,空缺按“0”補齊。
  • 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
  • 復制代碼 下面我們來參看并解讀下Tim大師的代碼:
  • awk '
  • FNR==1{? ? #FNR==1,即a和b文本的第一行,這個用的真的很巧妙。
  • ? ?? ???for(i=1;i<=NF;i++){?
  • ? ?? ?? ?? ?? ? b[i]=$i? ? #讀取文本的每個元素存入數組b
  • ? ?? ?? ?? ?? ? c[$i]++}??#另建立數組c,并統計每個元素的個數
  • ? ?? ?? ?? ?? ? next? ?? ?? ? #可以理解為,讀取FNR!=1的文本內容。
  • ? ?? ???}
  • {k++? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? # 統計除去第一行的文本行數
  • for(i=1;i<=NF;i++)a[k","b[i]]=$i??#利用一個二維數組來保持每個數字的位置, k,b[i]可以理解為每個數字的坐標。
  • }
  • END{
  • ? ?? ???l=asorti(c)? ?? ?? ? #利用asorti函數對數組的下標進行排序,并獲取數組長度,即輸出文件的列數(NF值)
  • ? ?? ???for(i=1;i<=l;i++)printf c[i]" " # 先打印第一行,相當于headline。
  • ? ?? ???print ""
  • ? ?? ???for(i=1;i<=k;i++){
  • ? ?? ?? ?? ?? ? for(j=1;j<=l;j++)printf a[i","c[j]]?a[i","c[j]]" ":"0 " # 打印二維數組的值。
  • ? ?? ?? ?? ?? ? print ""}
  • ? ?? ???}' a.txt b.txt
  • 復制代碼 8.??選擇性打印:
    打印某個關鍵字前幾行,以3行為例:
  • seq 20 |awk '/\<10\>/{for(i=NR-3;i<NR;i++)print a[i%3];exit}{a[NR%3]=$0}'
  • 7
  • 8
  • 9
  • 復制代碼 利用NR取余數,建立數組,這是一種非常高效的代碼。

    9. 通過split函數建立數組:數組的下標為從1開始的數字。
  • 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
  • 復制代碼 10. awk數組使用的小技巧和需要避免的用法:

    <1> 嵌套數組:
  • awk 'BEGIN{a[1]=3;b[1]=1;print a[b[1]]}'
  • 3
  • 復制代碼 <2> 下標設為變量或函數:
  • 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
  • 復制代碼 <3> 不可以將數組名作為變量使用,否則會報錯:
  • awk 'BEGIN{a["1"] = 3; delete a;a=3;print a}'??#即使你已經使用了delete函數。
  • awk: fatal: attempt to use array `a' in a scalar context
  • 復制代碼 <4> 數組的長度:
  • length(array)??
  • 復制代碼 <5> match 函數也可以建立數組(你知道么? ,版本要求高于gawk 3.1.2)
  • echo "foooobazbarrrrr |?
  • gawk '{ match($0, /(fo+).+(bar*)/, arr)??#匹配到的部分自動賦值到arr中,下標從1開始
  • ? ?? ?? ? print arr[1], arr[2]
  • ? ?? ?? ? print arr[1, "start"], arr[1, "length"]??#二維數組arr[index,"start"]值=RSTART
  • ? ?? ?? ? print arr[2, "start"], arr[2, "length"]??#二維數組arr[index,"length"]值=RLENGTH
  • ? ?? ?? ? }'
  • foooo barrrrr
  • 1 5
  • 9 7
  • 復制代碼 <6>想到過用split清空數組么?
  • 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] =
  • 復制代碼 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的awk 数组用法【精华贴】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。