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