• 山西新闻网特约摄影师名单&山西视觉志 2019-02-05
  • 广州旅游为何爆发出强大且持续的吸引力 2019-02-05
  • 今天看啥
      热点:

        北京赛车pk10历史记录 www.zwahn.com

        在文本处理的工作中,awk的数组是必不可少的工具,在这里,同样以总结经验和教训的方式和大家分享下我的一些学习心得,如有错误的地方,请大家指正和补充。


        awk的数组,一种关联数组(Associative Arrays),下标可以是数字和字符串。因无需对数组名和元素提前声明,也无需指定元素个数 ,所以awk的数组使用非常灵活。
        首先介绍下几个awk数组相关的知识点:

        <1>建立数组

        1.  
        2. array[index] = value :数组名array,下标index以及相应的值value。
        3.  
        复制代码

        <2>读取数组值

        1.  
        2. { for (item in array)  print array[item]} # 输出的顺序是随机的
        3. {for(i=1;i<=len;i++)  print array[i]} # Len 是数组的长度
        4.  
        复制代码

        <3>多维数组,array[index1,index2,……]:SUBSEP是数组下标分割符,默认为“\034”??梢允孪壬瓒⊿UBSEP,也可以直接在SUBSEP的位置输入你要用的分隔符,如:

        1.  
        2. awk 'BEGIN{SUBSEP=":";array["a","b"]=1;for(i in array) print i}'
        3. a:b
        4. awk 'BEGIN{array["a"":""b"]=1;for(i in array) print i}'
        5. a:b
        6.  
        复制代码

        但,有些特殊情况需要避免,如:

        1.  
        2. awk 'BEGIN{
        3. SUBSEP=":"
        4. array["a","b:c"]=1               # 下标为“a:b:c”
        5. array["a:b","c"]=2               #下标同样是“a:b:c”
        6. for (i in array) print i,array[i]}'
        7. a:b:c 2                                 #所以数组元素只有一个。
        8.  
        复制代码

        <4>删除数组或数组元素: 使用delete 函数

        1.  
        2. delete array                     #删除整个数组
        3. delete array[item]           # 删除某个数组元素(item)
        4.  
        复制代码

        <5> 排序:awk中的asort函数可以实现对数组的值进行排序,不过排序之后的数组下标改为从1到数组的长度。在gawk 3.1.2以后的版本还提供了一个asorti函数,这个函数不是依据关联数组的值,而是依据关联数组的下标排序,即asorti(array)以后,仍会用数字(1到数组长度)来作为下标,但是array的数组值变为排序后的原来的下标,除非你指定另一个参数如:asorti(a,b)。(非常感谢lionfun对asorti的指正和补充



        1.  
        2. echo 'aa
        3. bb
        4. aa
        5. bb
        6. cc' |\
        7. awk '{a[$0]++}END{l=asorti(a);for(i=1;i<=l;i++)print a[i]}'
        8. aa
        9. bb
        10. cc
        11.  
        12. echo 'aa
        13. bb
        14. aa
        15. bb
        16. cc' |\
        17. awk '{a[$0]++}END{l=asorti(a,b);for(i=1;i<=l;i++)print b[i],a[b[i]]}'
        18. aa 2
        19. bb 2
        20. cc 1
        21.  
        复制代码


        下面说awk数组的实际应用。

        1.  除去重复项, 这个不多说, 只给出代码:

        1.  
        2. awk '!a[$0]++' file(s)                   
        3. awk '!($0 in a){a[$0];print}' file(s)    
        4.  
        复制代码

        另一种://bbs.chinaunix.net/thread-1859344-1-1.html 

        2. 计算总数(sum),如:

        1.  
        2. awk  '{name[$0]+=$1};END{for(i in name) print  i, name[i]}'
        3.  
        4. 再举个例子:
        5.  
        6. echo "aaa 1
        7. aaa 1
        8. ccc 1
        9. aaa 1
        10. bbb 1
        11. ccc 1" |awk '{a[$1]+=$2}END{for(i in a) print i,a[i]}'
        12. aaa 3
        13. bbb 1
        14. ccc 2
        15.  
        16.  
        17.  
        复制代码

        3. 查看文件差异。

        1.  
        2. cat file1
        3. aaa
        4. bbb
        5. ccc
        6. ddd
        7. cat file2
        8. aaa
        9. eee
        10. ddd
        11. fff
        12.  
        复制代码

        <1>  合并file1和file2,除去重复项:

        1.  
        2. awk 'NR==FNR{a[$0]=1;print}   #读取file1,建立数组a,下标为$0,并赋值为1,然后打印
        3. NR>FNR{                   #读取file2
        4. if(!(a[$0])) {print }      #如果file2 的$0不存在于数组a中,即不存在于file1,则打印。
        5. }' file1 file2
        6. aaa
        7. bbb
        8. ccc
        9. ddd
        10. eee
        11. fff
        12.  
        复制代码

        <2> 提取文件1中有,但文件2中没有:

        1.  
        2. awk 'NR==FNR{a[$0]=1}           #读取file2,建立数组a,下标为$0,并赋值为1
        3. NR>FNR{                   #读取file1
        4. if(!(a[$0])) {print }      #如果file1 的$0不存在于数组a中,即不存在于file2,则打印。
        5. }' file2 file1
        6. bbb
        7. ccc
        复制代码

        另://bbs.chinaunix.net/viewthr ... &page=1#pid15547885 

        4.  排序:

        1.  
        2. echo "a
        3. 1
        4. 0
        5. b
        6. 2
        7. 10
        8. 8
        9. 100" |
        10. awk '{a[$0]=$0} #建立数组a,下标为$0,赋值也为$0
        11. END{
        12. len=asort(a)      #利用asort函数对数组a的值排序,同时获得数组长度len
        13. for(i=1;i<=len;i++) print i "\t"a[i]  #打印
        14. }'
        15. 1       0
        16. 2       1
        17. 3       2
        18. 4       8
        19. 5       10
        20. 6       100
        21. 7       a
        22. 8       b
        复制代码

        5.  有序输出:采用(index in array)的方式打印数组值的顺序是随机的,如果要按原序输出,则可以使用下面的方法://bbs2.chinaunix.net/viewthread.php?tid=1811279

        1.  
        2. awk '{a[$1]=$2
        3. c[j++]=$1}
        4. END{
        5. for(m=0;m<j;m++)print c[m],a[c[m]]
        6. }'
        7.  
        复制代码

        6.  多个文本编辑:这里主要指的是待处理的文本之间的格式上有区别,如分隔符不同,;或是待处理文本需提取的信息的位置不同,如不同的列或行。
        <例1>:

        1.  
        2. cat file1
        3. g1.1 2
        4. g2.2 4
        5. g2.1 5
        6. g4.1 3
        7. cat file2
        8. g1.1 2
        9. g1.2 3
        10. g4.1 4
        11. cat file3
        12. g1.2 3
        13. g5.1 3
        14.  
        复制代码

        要求输出:

        1.  
        2. g1.1 2 2 -
        3. g1.2 - 3 3
        4. g2.2 4 - -
        5. g2.1 5 - -
        6. g4.1 3 4 -
        7. g5.1 - - 3
        8.  
        复制代码

        实现代码如下:

        1.  
        2. awk '{a[ARGIND" "$1]=$2 # ARGIND是当前命令行文件的位置(从0开始),将它和第一列的value作为下标,建立数组a。
        3.        b[$1]   #将第一列的value作为下标,建立数组b,目的是在读完所有文件之后,能得到第一列value的uniqe-list。
        4.         }
        5. END{ 
        6.         for(i in b) { 
        7.                 printf i" " 
        8.                 for(j=1;j<=ARGIND;j++) printf "%s ", a[j" "i]?a[j" "i]:"-" #此时的ARGIND值为3.
        9. print "" 
        10.                 }
        11.         }' file1 file2 file3
        12.  
        复制代码

        这里是利用awk的内置变量ARGIND来处理完成对文件的处理。关于ARGIND,ARGV,ARGC的使用,大家可以参考://bbs.chinaunix.net/viewthr ... 0335&from=favorites。
        当然,我们也可以利用另外一个内置变量FILENAME来完成相同的任务(大家可以先想想怎么写),如下:

        1.  
        2. 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
        3.  
        复制代码

        <例2>:对上面的数据的格式稍作改动,每个文件的分隔符都一样的情况,但输出要求不变:

        1.  
        2. cat file1
        3. g1.1|2
        4. g2.2|4
        5. g2.1|5
        6. g4.1|3
        7. cat file2
        8. g1.1#2
        9. g1.2#3
        10. g4.1#4
        11. cat file3
        12. [email protected]
        13. [email protected]
        14.  
        复制代码

        实现代码如下:

        1.  
        2. awk '{a[ARGIND" "$1]=$2
        3. b[$1]
        4. }
        5. END{
        6. for(i in b) {
        7. printf i" "
        8. for(j=2;j<=ARGIND;j+=2) printf "%s ", a[j" "i]?a[j" "i]:"-" # 由于FS的设置也是有对应ARGIND值,所以对ARGIND稍作改动。
        9. print ""
        10. }
        11. }' FS="|" file1 FS="#" file2 FS="@" file3 # 对每个文件分别设置FS的值。
        12.  
        复制代码

        因为这个例子的数据比较简单,我们也可以在BEGIN??橹型瓿啥訤S值设置,如下:

        1.  
        2. 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
        3.  
        复制代码

        利用FILENAME 同样可以解决问题:

        1.  
        2. awk '
        3. FILENAME=="file1"{FS="|"}    # 设置FS
        4. FILENAME=="file2"{FS="#"}   #设置FS
        5. FILENAME=="file3"{FS="@"}  #设置FS 
        6. # 稍显繁琐,不过一目了然
        7. {$0=$0}                                   #使FS生效。
        8. {a[ARGIND" "$1]=$2; b[$1]}
        9. END{ for(i in b) {printf i" "; for(j=1;j<=ARGIND;j++) printf "%s ", a[j" "i]?a[j" "i]:"-"; print ""}
        10. }' file1 file2 file3
        11.  
        复制代码

        推荐一个关于数组处理文件的帖子//www.chinaunix.net/jh/24/577044.html ,里面有不少例子供大家学习。

        7.  文本翻转或移位:二维或多维数组的应用
        <例1>:

        1.  
        2. Inputfile
        3. 1 2 3 4 5 6
        4. 2 3 4 5 6 1
        5. 3 4 5 6 1 2
        6. 4 5 6 1 2 3
        7. Outputfile
        8. 4 3 2 1
        9. 5 4 3 2
        10. 6 5 4 3
        11. 1 6 5 4
        12. 2 1 6 5
        13. 3 2 1 6
        14.  
        15. awk '{
        16.      if (max_nf < NF)
        17.           max_nf = NF # 数组第一维的长度
        18.      max_nr = NR      # 数组第二维的长度
        19.      for (x = 1; x <= NF; x++)
        20.           vector[x, NR] = $x #建立数组vector
        21. }
        22. END {
        23.      for (x = 1; x <= max_nf; x++) {
        24.           for (y = max_nr; y >= 1; --y)
        25.                printf("%s ", vector[x, y])
        26.           printf("\n")
        27.      }
        28. }' 
        29.  
        复制代码

        <例2>:来自//bbs.chinaunix.net/viewthr ... &page=1#pid13339226
        有两个文本a和b,要求输出c文本,合并的规则是按照第一行的headline(按字母顺序)合并文本a和b,空缺按“0”补齐。

        1.  
        2. cat a.txt
        3. a b c d
        4. 1 2 9 7
        5. 4 5 8 9
        6. 5 3 6 1
        7. cat b.txt
        8. a e f d g
        9. 9 2 4 7 3
        10. 4 3 7 9 4
        11. cat c.txt
        12. a b c d e f g
        13. 1 2 9 7 0 0 0
        14. 4 5 8 9 0 0 0
        15. 5 3 6 1 0 0 0
        16. 9 0 0 7 2 4 3
        17. 4 0 0 9 3 7 4
        18.  
        复制代码

        下面我们来参看并解读下Tim大师的代码:

        1.  
        2. awk '
        3. FNR==1{    #FNR==1,即a和b文本的第一行,这个用的真的很巧妙。
        4.         for(i=1;i<=NF;i++){ 
        5.                 b[i]=$i    #读取文本的每个元素存入数组b
        6.                 c[$i]++}  #另建立数组c,并统计每个元素的个数
        7.                 next          #可以理解为,读取FNR!=1的文本内容。
        8.         }
        9. {k++                                     # 统计除去第一行的文本行数
        10. for(i=1;i<=NF;i++)a[k","b[i]]=$i  #利用一个二维数组来保持每个数字的位置, k,b[i]可以理解为每个数字的坐标。
        11. }
        12. END{
        13.         l=asorti(c)          #利用asorti函数对数组的下标进行排序,并获取数组长度,即输出文件的列数(NF值)
        14.         for(i=1;i<=l;i++)printf c[i]" " # 先打印第一行,相当于headline。
        15.         print ""
        16.         for(i=1;i<=k;i++){
        17.                 for(j=1;j<=l;j++)printf a[i","c[j]]?a[i","c[j]]" ":"0 " # 打印二维数组的值。
        18.                 print ""}
        19.         }' a.txt b.txt
        20.  
        复制代码

        8.  选择性打?。?/span>
        打印某个关键字前几行,以3行为例:

        1.  
        2. seq 20 |awk '/\<10\>/{for(i=NR-3;i<NR;i++)print a[i%3];exit}{a[NR%3]=$0}'
        3. 7
        4. 8
        5. 9
        6.  
        复制代码

        利用NR取余数,建立数组,这是一种非常高效的代码。

        9. 通过split函数建立数组:数组的下标为从1开始的数字。

        1.  
        2. split(s, a [, r]) # s:string, a:array name,[,r]:regular expression。
        3. echo 'abcd' |awk '{len=split($0,a,"");for(i=1;i<=len;i++) print "a["i"] = " a[i];print "length = " len}'
        4. a[1] = a
        5. a[2] = b
        6. a[3] = c
        7. a[4] = d
        8. length = 4 
        9.  
        复制代码

        10. awk数组使用的小技巧和需要避免的用法:

        <1> 嵌套数组:

        1.  
        2. awk 'BEGIN{a[1]=3;b[1]=1;print a[b[1]]}'
        3. 3
        4.  
        复制代码

        <2> 下标设为变量或函数:

        1.  
        2. awk 'BEGIN{s=123;a[substr(s,2)]=substr(s,1,1);for(i in a)print "index : "i"\nvalue : "a[i]}'
        3. index : 23
        4. value : 1 
        5.  
        复制代码

        <3> 不可以将数组名作为变量使用,否则会报错:

        1.  
        2. awk 'BEGIN{a["1"] = 3; delete a;a=3;print a}'  #即使你已经使用了delete函数。
        3. awk: fatal: attempt to use array `a' in a scalar context
        4.  
        复制代码

        <4> 数组的长度:

        1.  
        2. length(array)  
        3.  
        复制代码

        <5> match 函数也可以建立数组(你知道么?,版本要求高于gawk 3.1.2)

        1.  
        2. echo "foooobazbarrrrr | 
        3. gawk '{ match($0, /(fo+).+(bar*)/, arr)  #匹配到的部分自动赋值到arr中,下标从1开始
        4.           print arr[1], arr[2]
        5.           print arr[1, "start"], arr[1, "length"]  #二维数组arr[index,"start"]值=RSTART
        6.           print arr[2, "start"], arr[2, "length"]  #二维数组arr[index,"length"]值=RLENGTH
        7.           }'
        8. foooo barrrrr
        9. 1 5
        10. 9 7
        11.  
        复制代码

        <6>想到过用split清空数组么?

        1.  
        2. awk 'BEGIN{
        3. split("abc",array,"")
        4. print "array[1] = "array[1],"\narray[2] = "array[2],"\narray[3] = "array[3]
        5. split("",array)
        6. print "array[1] = "array[1],"\narray[2] ="array[2],"\narray[3] ="array[3]
        7. }'
        8. array[1] = a
        9. array[2] = b
        10. array[3] = c
        11. array[1] =
        12. array[2] =
        13. array[3] =
        14.  
        复制代码

        北京赛车pk10历史记录 www.zwahn.comtrue//www.zwahn.com/Linuxjc/1316472.htmlTechArticle在文本处理的工作中,awk的数组是必不可少的工具,在这里,同样以总结经验和教训的方式和大家分享下我的一些学习心得,如有错误的地...

        相关文章

          暂无相关文章
        相关搜索:

        帮客评论

        视觉看点
      • 山西新闻网特约摄影师名单&山西视觉志 2019-02-05
      • 广州旅游为何爆发出强大且持续的吸引力 2019-02-05