天天看点

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

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    2050
sunboy    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 = 7
5 = 9
1 = 1
2 = 3
3 = 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.txt
Tom    2012-12-11      car     53000
John   2013-01-13      bike    41000
vivi    2013-01-18      car     42800
Tom    2013-01-20      car     32500
John   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 2800
Tom2500
John4500      

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

日志:
[08-09 17:13:22] [INFO] [com.abc.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 125
ddd 123
bbb 128
ccc 120

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

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