awk数组和split函数、asort和asorti 排序函数

来源:互联网 发布:我爸是李刚真相知乎 编辑:程序博客网 时间:2024/06/12 00:58

awk 中数组叫做关联数组(associative arrays),下标可以是数字也可以是字符串。awk 中的数组不必提前声明,也不必声明大小,初始化数组元素用 0 或空串,这根据上下文而定。

1、一维数组:

#!/bin/bash    awk 'BEGIN{  array[1]="it"  array[2]="homer"  array[3]="sunboy"  array[4]=2050      array["first"]="yang"  array["second"]="gang"  array["third"]="sunboy"      print array[1], array[4]  print array[3], array["third"]}' 结果:it    2050sunboy    sunboy

#!/bin/bash    awk 'BEGIN{     for(i=1; i<=5; i++){         array[i] = i*2 - 1;     }       for(i in array){         print i" = " array[i];     }  }'  结果:4 = 75 = 91 = 12 = 33 = 5

注意:使用for in循环输出数组时,不保证数组下表的顺序

2、二维数组:

awk 多维数组在本质上是一维数组,因awk在存储上并不支持多维数组,awk提供了逻辑上模拟二维数组的访问方式。例如,array[2,3] = 1这样的访问是允许的。
awk使用一个特殊的字符串SUBSEP (\034)作为分割字段,在上面的例子 array[2,3] = 1 中,关联数组array存储的键值实际上是2\0343,2和3分别为下标(2,3),\034为SUBSEP分隔符
类似一维数组的成员测试,多维数组可以使用 if ( (i,j) in array) 语法,但是下标必须放置在圆括号中。
类似一维数组的循环访问,多维数组使用 for ( item in array ) 语法遍历数组。与一维数组不同的是,多维数组必须使用split()函数来访问单独的下标分量,格式: split ( item, subscr, SUBSEP), 例如: split (item, array2, SUBSEP); 后,array2[1]为下标“2”, array2[2]为下标“3”

#!/bin/bash    awk 'BEGIN{     for(i=1; i<=3; i++){         for(j=1; j<=3; j++){             array[i, j] = i * j;             print i" * "j" = "array[i,j];         }     }       print       for(i in array){         split(i, array2, SUBSEP);         print array2[1]" * "array2[2]" = " array[i];     }  }'  
结果:

1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9

2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3


: 示例中 split(i, array2, SUBSEP); 即是把二维数组作为一维数组处理,同样数组元素顺序不确定,下面将介绍数组排序


3、split函数:

1)awk的内建函数split允许你把一个字符串分隔为不同元素并存储在数组中。你可以自己定义域分隔符或者使用现在FS(域分隔符)的值。
语法:

split (string, array, field separator)split (string, array)  -->如果第三个参数没有提供,awk就默认使用当前FS值。
2)返回值:split函数会返回拆分后数组的长度;

注:length(arr)函数也会返回数组的长度;

实例:计算指定范围内的和(计算每个人1月份的工资之和)

[root@test ~]# cat test.txtTom    2012-12-11      car     53000John   2013-01-13      bike    41000vivi    2013-01-18      car     42800Tom    2013-01-20      car     32500John   2013-01-28      bike    63500[root@test ~]# awk '{split($2,a,"-");if(a[2]==01){b[$1]+=$4}}END{for(i in b)print i,b[i]}' test.txt  vivi 2800Tom2500John4500

注:数组的下标是从1开始的,这一点和awk取各个列是一样的,如:第一列是$1。

日志:[08-09 17:13:22] [INFO] [com.iqiyi.ttbrain.recommend.api.controller.PersonalRecommendController:201] personalRecommend(): cost=20ms; puid=; uId=9A4BE58CAB9F490B45CC230C701432BE; fnum=11; chId=12; usg=0; recId=[334108380570, 281989490570, 290946800570, 315460740570, 310639020570, 310632450570, 86623440570, 325422890570, 324719760570, 323283300570, 325696980570]; mutilFeeds={"p_7":[334108380570],"p_3":[281989490570,290946800570,315460740570,310639020570,310632450570,86623440570,325422890570,324719760570,323283300570,325696980570]}; typeFeeds={"VIDEO":[334108380570,281989490570,290946800570,315460740570,310639020570,310632450570,86623440570,325422890570,324719760570,323283300570,325696980570]}; prefMap={324719760570:"电子相册 ",310639020570:"台球",86623440570:"小胡,车模,雪佛兰",334108380570:"金泫雅",290946800570:"嫩模,写真",325696980570:"林志玲,内衣秀",323283300570:"女生,醉酒,表白",325422890570:"伤心的人别去巡山,西游记,雷人",281989490570:"爆炸",315460740570:"单身狗",310632450570:"自我介绍"}; prior=null; reqUniqId=15022700029111778352589A4BE58CAB9F490B45CC230C701432BE; version=; flag=per_rec; rg=0; rh=9; pg=0; ph=0; sg=1; sh=0; strategy=rec,ctr,ltr,szhou统计fnum和rec_id长度:tail -f /data/logs/ttbrain/ttbrain-recommend-api.log | grep 'personalRecommend()' | awk -F'personalRecommend()' 'BEGIN{diff=0;} {split($2,a,";");split(a[4],fnum,"=");print fnum[2],split(a[7],array,",")}'

4、数组的排序:

asort 是对数组的值进行排序,并且会丢掉原先键值;
asorti是对数组的键值进行排序。

$ cat file aaa 125ddd 123bbb 128ccc 120$ awk '{a[$2]=$0}END{for(i=1;i<=asort(a);i++)print a[i]}' file aaa 125bbb 128ccc 120ddd 123$ awk '{a[$2]=$0}END{for(i=1;i<=asorti(a,b);i++)print a[b[i]]}' file ccc 120ddd 123aaa 125bbb 128

注:for…in循环输出时候,默认打印出来是无序数组。