免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 45688 | 回复: 14
打印 上一主题 下一主题

[学习共享] awk的数组之升级版 [复制链接]

论坛徽章:
2
射手座
日期:2014-10-10 15:59:4715-16赛季CBA联赛之上海
日期:2016-03-03 10:27:14
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-07-25 16:51 |只看该作者 |倒序浏览
本帖最后由 yinyuemi 于 2016-07-26 10:23 编辑

好久没发帖了,今天来策一策awk的数组升级版,参考自https://www.gnu.org/software/gawk/manual/gawk.html#Arrays
awk数组的基本用法,这里就不再赘述了(3.0+版本数组的主要用法在这里http://bbs.chinaunix.net/thread-2312439-1-1.html),这里主要讲是gawk4.0+版本中关于数组的2种新用法,所以还没有升级版本的筒子们赶快动起来吧。

1. 预定义遍历的数组

一般情况下,用for item in array的方法输出数组的值,其顺序是没有定义的,也就是”乱序的“。但是很多时候,我们希望
数组的值按照一定的要求输出,比如按照数值大小升序或降序的方式等等。此时,一般的做法,是通过asort或asorti来间接实现。
不过,现在好了,gawk4.0+版本提供了非常方便的对数组输出的控制模式。
这里涉及到一个gawk的一个内置数组PROCINFO,大家可以运行这个查看它的详细信息:
  1. awk 'BEGIN{for(i in PROCINFO){if(isarray(PROCINFO[i])){for( j in PROCINFO[i])print i,j,PROCINFO[i][j]}else{print i,PROCINFO[i]}}}'
复制代码
其中控制数组遍历模式的是"sorted_in",如下面的列表:

ROCINFO ["sorted_in"]        Description
@unsorted        Array indexes are processed in arbitrary order (default awk behavior).
@ind_str_asc        The array is sorted with indexes compared as strings in ascending order.
@ind_num_asc        The array is sorted with indexes compared as numbers in ascending order. Non-numeric indexes are treated as zero.
@val_type_asc        The array is sorted based on values as per its type in ascending order. All numbers come before the strings. The sub-arrays come after the strings.
@val_str_asc        The array is sorted based on values of elements, treating the values as strings, in ascending order.
@val_num_asc        The array is sorted based on values of elements, treating values as numbers, in ascending order.
@ind_str_desc        The array is sorted based on index, treated as strings, in descending order.
@ind_num_desc        The array is sorted based on index, treated as numbers, in descending order.
@val_type_desc        The array is sorted based on the value of the element as per its type in descending order. Subarrays come first, then the strings and lastly, the numbers.
@val_str_desc        The array is sorted based on element values, treated as strings, in descending order.
@val_num_desc        The array is sorted based on values, treated as numbers, in descending order.

一言不合举栗子:
  1. # 默认方式,即无序

  2. awk '
  3. BEGIN {PROCINFO ["sorted_in"] = "@unsorted"

  4.     fruit ["apple"] = 4
  5.     fruit ["mango"] = 12
  6.     fruit ["guava"] = 8
  7.     fruit ["banana"] = 16

  8.     for (j in fruit)
  9.         printf ("%s: %d numbers\n", j, fruit [j])
  10. } '

  11. guava: 8 numbers
  12. mango: 12 numbers
  13. apple: 4 numbers
  14. banana: 16 numbers

复制代码
  1. # 按照value的大小升序

  2. awk '
  3. BEGIN {PROCINFO ["sorted_in"] = "@val_num_asc"

  4.     fruit ["apple"] = 4
  5.     fruit ["mango"] = 12
  6.     fruit ["guava"] = 8
  7.     fruit ["banana"] = 16

  8.     for (j in fruit)
  9.         printf ("%s: %d numbers\n", j, fruit [j])
  10. } '

  11. apple: 4 numbers
  12. guava: 8 numbers
  13. mango: 12 numbers
  14. banana: 16 numbers

复制代码
  1. # 按照index字母顺序降序

  2. awk '
  3. BEGIN {PROCINFO ["sorted_in"] = "@ind_str_desc"

  4.     fruit ["apple"] = 4
  5.     fruit ["mango"] = 12
  6.     fruit ["guava"] = 8
  7.     fruit ["banana"] = 16

  8.     for (j in fruit)
  9.         printf ("%s: %d numbers\n", j, fruit [j])
  10. } '


  11. mango: 12 numbers
  12. guava: 8 numbers
  13. banana: 16 numbers
  14. apple: 4 numbers

复制代码
俗话说,”栗子不过三“,就举到这里先。
是不是觉得asort/asorti在这个sorted_in”控制阀“面前弱爆了?!
友情提示: 因为PROCINFO ["sorted_in"]是全局性的变量,一旦设定之后,会改变整个awk的数组遍历方式,所以如果你希望在小范围内使用,可以按照下面的方式来做。


  1. if ("sorted_in" in PROCINFO) {
  2.     save_sorted = PROCINFO["sorted_in"]
  3.     PROCINFO["sorted_in"] = "@val_str_desc" # or whatever
  4. }

  5. if (save_sorted)
  6.     PROCINFO["sorted_in"] = save_sorted

复制代码
事实上,除了awk内置的遍历函数,sorted_in也可以被赋予自定义的函数。
自定义的函数有个通用的代码框架如下:

  1. function comp_func(i1, v1, i2, v2) # 至少包含4个参数
  2. {
  3.     compare elements 1 and 2 in some fashion
  4.     return < 0; 0; or > 0
  5. }
复制代码
栗子如下:

  1. awk '

  2. BEGIN{
  3.     arr[1] = 10
  4.     arr[2] = 2
  5.     arr[3] = 100
  6.         arr["one"] = 10
  7.         arr["two"] = 1
  8.         arr["three"] = 100
  9.     PROCINFO["sorted_in"] = "cmp_num_val_desc"
  10.     print "#exactly the same as @val_num_desc"
  11.     for(i in  arr)
  12.         print "arr["i"] = " arr[i]

  13.     print "如果排序规则改为:1. index:字母在前,数字之后    2. index一致时, value降序"
  14.     PROCINFO["sorted_in"] = "cmp_smart_desc"
  15.     print "#sort in a smarter way"
  16.         for(i in  arr)
  17.         print "arr["i"] = " arr[i]
  18. }
  19. function cmp_num_val_desc(i1, v1, i2, v2)
  20. {
  21.     # numerical value comparison, descending order,
  22.     return (v2 - v1)
  23. }


  24. function cmp_smart_desc(i1, v1, i2, v2,   n1, n2)
  25. {
  26.      # numbers after string value comparison, descending order
  27.      n1 = i1 + 0
  28.      n2 = i2 + 0
  29.      if (n1 != i1)
  30.          return (n2 != i2) ? (v2 - v1) : -1
  31.      else if (n2 != i2)
  32.          return 1
  33.      return v2 - v1
  34. }
  35. '


  36. #exactly the same as @val_num_desc
  37. arr[three] = 100
  38. arr[3] = 100
  39. arr[one] = 10
  40. arr[1] = 10
  41. arr[2] = 2
  42. arr[two] = 1
  43. 如果排序规则改为:1. index:字母在前,数字之后    2. index一致时, value降序
  44. #sort in a smarter way
  45. arr[three] = 100
  46. arr[one] = 10
  47. arr[two] = 1
  48. arr[3] = 100
  49. arr[1] = 10
  50. arr[2] = 2

复制代码
2. 数组的数组 (Arrays of Arrays)

有了它,awk就可以真正创建多维数组,而不像以前版本那样用一维数组来模拟多维。
如果有童鞋对perl的hash熟悉的话,那么它可以理解为hash of hash。

下面先看“数组的数组”活生生的样子吧

  1. a[1][1]=1
  2. a[1][2]=2
  3. a[1][3]=3
复制代码
是不是很眼熟,在某种/些语言里有相同的写法。
没错,这就是一个典型的二维数组,第一维的index为[1],第二维为[1][2][3]。
事实上,为了保持每一维度在index使用的灵活性,对于下面的写法也是继续支持的:

  1. a[1][1,"a"]=1
  2. a[1][2,"a"]=2
  3. a[1][3,"a"]=3
复制代码
并且,每一维数组的value可以是一个scalar,也可以是一个subarray

  1. a[1][1,"a"]=1
  2. a[2]=2
  3. a[3][3][4]=3
复制代码
好了,说了这么多,如何打印Arrays of Arrays呢?其实很简单~

  1. for (i in array)
  2.     for (j in array[i])
  3.         print array[i][j]
复制代码
当你不知道某个维度的value是scalar,还是subarray,那么可以加个判断。
如何判断呢?也很简单,因为新版gawk已经帮你写好函数,就等你用了,它就是isarray。
官方文档还配备了一个残暴的walk_array, 简直是无所不至。

  1. function walk_array(arr, name,      i)
  2. {
  3.     for (i in arr) {
  4.         if (isarray(arr[i]))
  5.             walk_array(arr[i], (name "[" i "]"))
  6.         else
  7.             printf("%s[%s] = %s\n", name, i, arr[i])
  8.     }
  9. }
复制代码
好久没有写文档了,一口气写了这么多,感觉身体快被掏空 不多说了,再打一套以上两个新功能的“组合拳”就结贴了!
模拟sort排序

  1. cat file
  2. abc 123 100
  3. abc 456 100
  4. abc 456 10
  5. def 123 10
  6. def 123 100
  7. abc 123 1
  8. xzy 789 0


  9. # sort 排序: 第一列按照字母升序,第二列数字升序,第三列数字降序

  10. sort -k1,1 -k2,2n -k3,3nr file
  11. abc 123 100
  12. abc 123 1
  13. abc 456 100
  14. abc 456 10
  15. def 123 100
  16. def 123 10
  17. xzy 789 0


  18. # awk 3.0+ 排序

  19. awk '
  20. {
  21.     a[$1" "$2" "$3];
  22.         b[$1]=$1;
  23.         c[$2];
  24.         d[$3]
  25. }
  26. END{
  27.         for(i=1;i<=asort(b);i++)
  28.                 for(j=1;j<=asorti(c,e);j++)
  29.                         for(k=asorti(d,f);k>=1;k--)
  30.                                 if(b[i]" "e[j]" "f[k] in a)
  31.                                         print b[i],e[j],f[k]
  32. }
  33. ' file
  34. abc 123 100
  35. abc 123 1
  36. abc 456 100
  37. abc 456 10
  38. def 123 100
  39. def 123 10
  40. xzy 789 0



  41. # gawk 4.0+ 排序

  42. awk '
  43. {
  44.     arr[$1][$2][$3]
  45. }
  46. END{
  47.     PROCINFO["sorted_in"] = "@ind_str_asc"
  48.     for(i in arr){
  49.         PROCINFO["sorted_in"] = "@ind_num_asc"
  50.         for(j in arr[i]){
  51.             PROCINFO["sorted_in"] = "@ind_num_desc"
  52.             for(k in arr[i][j])
  53.                 print i,j,k
  54.         }
  55.     }
  56. }
  57. ' file

  58. abc 123 100
  59. abc 123 1
  60. abc 456 100
  61. abc 456 10
  62. def 123 100
  63. def 123 10
  64. xzy 789 0


复制代码
两种awk的写法相比,gawk的是不是更加清晰,明了呢


艾玛呀,终于写完了,希望能给大家一些启示和帮助,抛砖引玉,如有错误的地方,请不吝指正!

最后还想说的是gawk4.0版本还有很多fancy的功能,有兴趣的可以翻翻 http://bbs.chinaunix.net/thread-3559813-1-1.html



评分

参与人数 10可用积分 +5 信誉积分 +90 收起 理由
关阴月飞 + 10 牛,学习了,求工作!!
zsszss0000 + 10 赞一个!
expert1 + 5 很给力!
liion631818 + 10 大神出马,一个顶百
WilliBhamlll + 10 很给力!
jcdiy0601 + 10 赞一个!
blackold + 10 赞一个!
songyc_2015 + 10 向s博学习
reyleon + 10 S博的文章必须赞啊
Herowinter + 10 向大神学习!

查看全部评分

论坛徽章:
5
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015年亚洲杯之朝鲜
日期:2015-03-13 22:47:33IT运维版块每日发帖之星
日期:2016-01-09 06:20:00IT运维版块每周发帖之星
日期:2016-03-07 16:27:44
2 [报告]
发表于 2016-07-25 17:10 |只看该作者
@yinyuemi 赞!!! 学习了。

论坛徽章:
2
射手座
日期:2014-10-10 15:59:4715-16赛季CBA联赛之上海
日期:2016-03-03 10:27:14
3 [报告]
发表于 2016-07-25 17:42 |只看该作者
回复 2# blackold


    黑哥,谦虚啦,多指正补充啊!

论坛徽章:
20
卯兔
日期:2015-01-26 22:05:142015亚冠之萨济拖拉机
日期:2015-09-10 15:15:282015亚冠之阿尔希拉尔
日期:2015-09-25 17:37:53程序设计版块每日发帖之星
日期:2015-10-03 06:20:00程序设计版块每日发帖之星
日期:2015-12-09 06:20:00CU十四周年纪念徽章
日期:2015-12-17 09:07:15程序设计版块每日发帖之星
日期:2015-12-25 06:20:34程序设计版块每日发帖之星
日期:2015-12-25 06:20:34程序设计版块每日发帖之星
日期:2015-12-25 06:20:342015亚冠之广州富力
日期:2015-08-27 19:29:56每日论坛发贴之星
日期:2015-08-26 06:20:002015亚冠之阿尔希拉尔
日期:2015-05-18 17:26:27
4 [报告]
发表于 2016-07-25 18:16 |只看该作者
先点赞后学习

论坛徽章:
60
20周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之北京
日期:2016-07-06 15:42:0715-16赛季CBA联赛之同曦
日期:2016-06-12 10:38:0915-16赛季CBA联赛之佛山
日期:2016-05-27 11:54:56黄金圣斗士
日期:2015-12-02 11:44:35白银圣斗士
日期:2015-11-25 14:32:43白银圣斗士
日期:2015-11-23 12:53:352015亚冠之布里斯班狮吼
日期:2015-10-21 16:55:482015亚冠之首尔
日期:2015-09-01 16:46:052015亚冠之德黑兰石油
日期:2015-08-31 11:39:192015亚冠之萨济拖拉机
日期:2015-08-28 21:06:5315-16赛季CBA联赛之广东
日期:2016-07-12 14:58:53
5 [报告]
发表于 2016-07-25 18:24 |只看该作者
明日再细阅, 今天的酱油打完了, go home ...

论坛徽章:
0
6 [报告]
发表于 2016-07-25 22:49 |只看该作者
先回复了再学习,谢谢lz

论坛徽章:
6
羊年新春福章
日期:2015-03-03 17:16:28双子座
日期:2015-03-03 17:16:56巳蛇
日期:2015-03-03 17:17:2415-16赛季CBA联赛之福建
日期:2016-03-11 09:05:00黑曼巴
日期:2016-07-07 16:58:1215-16赛季CBA联赛之吉林
日期:2016-11-14 09:23:07
7 [报告]
发表于 2016-07-26 09:50 |只看该作者
向大师学习,给分收藏,慢慢消化

论坛徽章:
2
子鼠
日期:2014-12-09 14:03:562015年亚洲杯之巴勒斯坦
日期:2015-03-31 10:49:39
8 [报告]
发表于 2016-07-26 10:52 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
16
IT运维版块每日发帖之星
日期:2015-08-24 06:20:00综合交流区版块每日发帖之星
日期:2015-10-14 06:20:00IT运维版块每日发帖之星
日期:2015-10-25 06:20:00IT运维版块每日发帖之星
日期:2015-11-06 06:20:00IT运维版块每日发帖之星
日期:2015-12-10 06:20:00平安夜徽章
日期:2015-12-26 00:06:302016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-04-15 06:20:00IT运维版块每日发帖之星
日期:2016-05-21 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-14 06:20:00
9 [报告]
发表于 2016-07-26 12:39 |只看该作者
学习,ss大师总是走在时代前沿啊,4.0都用了。

求职 : 机器学习
论坛徽章:
79
2015年亚洲杯纪念徽章
日期:2015-05-06 19:18:572015七夕节徽章
日期:2015-08-21 11:06:172015亚冠之阿尔纳斯尔
日期:2015-09-07 09:30:232015亚冠之萨济拖拉机
日期:2015-10-21 08:26:3915-16赛季CBA联赛之浙江
日期:2015-12-30 09:59:1815-16赛季CBA联赛之浙江
日期:2016-01-10 12:35:21技术图书徽章
日期:2016-01-15 11:07:2015-16赛季CBA联赛之新疆
日期:2016-02-24 13:46:0215-16赛季CBA联赛之吉林
日期:2016-06-26 01:07:172015-2016NBA季后赛纪念章
日期:2016-06-28 17:44:45黑曼巴
日期:2016-06-28 17:44:4515-16赛季CBA联赛之浙江
日期:2017-07-18 13:41:54
10 [报告]
发表于 2016-07-26 14:21 |只看该作者
顶一下。。。。。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP