awk数组详解

awk数组详解

一般我们是通过数组的下标(或者称索引),引用数组中的元素,有一些语言中,数组的下标由0开始,也就是说,如果想要引用数组中的第1个元素,则需要引用对就的下标”[0]”,awk中的数组也是通过引用下标的方法,获取数组中的元素的,但是在awk中,数组元素的下标默认是从1开始,但是为了兼容你的使用习惯,也可以从0开始设置下标。

在其它语言中,我们一般要先声明一个数组,在awk中我们可以直接为数组中的元素赋值如:

1
awk 'BEGIN{test[0]=1;test[1]=2;test[2]=3;print test[1]}'

上例中我们使用了BEGIN模式,其中有一个test数组,如果想要引用里面的值,只要用数组名加下标即可。linux中,命令行的换行符为反斜杠”"。

我们也可以把数组的元素值设置为”空字符串”。如:

1
2
3
awk 'BEGIN{test[0]=1;test[1]=2;test[2]="";print test[2]}'

注:上面一行没有东西输出是空值

当我们打印数组的第2个元素的值时,打印的值就是空(注:空格不为空)

根据以上说明:在awk中,将元素的值设置为”空字符串”是合法的。

在awk中,元素的值可以为空,那么我们就不能再根据元素的值是否为”空”去判断元素是否存在了。如:

1
2
awk 'BEGIN{test[0]=1;test[1]=2;test[2]="";if (test[2]=="")print "数组第3个元素不存在"}'
这是一种错误的写法

还有另外一个原因,就是当一个元素不存在于数组时,如果我们直接引用这个不存在的元素,awk会自动创建这个元素,并且默认认为这个元素赋值为“空字符串”,示例如下:

1
2
3
awk 'BEGIN{test[0]=1;test[1]=2;test[2]="";{print test[3]}}'

上面一行没有东西输出是空值

如上,数组中没有第4个元素,但是当我们输出第4个元素是,输出了空,所以,出于此原因,在awk中使用之前的方法判断元素是否为空也是不合理的,因为当我们引用一个不存在的数组中的元素时,这个元素其实已经被赋值为“空字符串”了。如:

1
2
awk 'BEGIN{test[0]=1;test[1]=2;test[2]="";if(test[3]==""){print "数组第4个元素不存在 "}'
数组的第4个元素不存在

上面写法是错的怎样判断元素是否存在,我们使用如下语法:

1
awk 'BEGIN{test[0]=1;test[1]=2;test[2]="";if(2 in test){print "数组第3个元素存在 "}'

如上我们可以使用语法”if(下标 in 数组名)”,从而判断数组中是否存在对应的元素。当然我们可以使用”!”对条件进行取反,如:

1
awk 'BEGIN{test[0]=1;test[1]=2;test[2]="";if(!(2 in test)){print "数组第3个元素不存在 "}'

在awk中,数组的下标不仅可以为”数字”,还可以为”任意字符串”,如果你使用过shell中的数组,你可以把awk的数组比作bash中的”关联数组”,如:

1
awk 'BEGIN{test["jon"];test["son"]}'

其实,awk中的数组本来就是”关联数组”,之所以先用以数字作为下标的数组举例,是为了让读者能够更好的过度,不过,以数字作为数组下标的数组在某些场景有一定的优势,但是它本质也是关联数组,awk默认会把”数字”下标转换为”字符串”,所以本质上它还是一个使用字符串作为下标的关联数组。

使用delete可以删除数组中的元素,如下:

1
2
awk 'BEGIN{test["jon"]="j";test["son"]="s";delete test["son"];print test["son"]}'
#为空,也可以使用delete删除整个数组"delete 数组名"

在awk中想要输出数组中的所有元素,则需要借助for循环语句,有两种for循环语法如:

1
2
3
4
5
6
7
8
9
#for循环语法格式1
for(初始化; 布尔表达式; 更新) {
//代码语句
}
 
#for循环语法格式2
for(变量 in 数组) {
//代码语句
}

这两种for循环都能够遍历出数组中的元素,不过第一种for循环只能输出以数字作为下标的数组,如:

1
2
3
awk 'BEGIN{test[1]="jon";test[2]="son"for(i=1;i<=2;i++){print i,test[i]};}'
1 jon
2 son

利用for循环中的变量”i“数组中的下标都是数字的这一特性,按照顺序输出了数组中的元素值。

当数组中的元素的下标为”无规律的字符串“时,我们就可心使用for循环的第二种语法。

1
awk 'BEGIN{test[1]="jon";test[2]="son"for(i in test){print i,test[i]};}'

注意,在这种语法中,for循环中的变量”i“表示的是元素的下标,而并非表示元素的值,所以,如果想要输出元素的值,则需要使用print 数组名[变量]。

当数组中的下标为字符串时,元素值输出的顺序与元素在数组中的顺序不同,这是因为awk中的数组本质上是关联数组,所以默认打印出来的元素是无序的。

实际应用

在实际工作中,我们往往会使用数组,统计某些字符出现的次数,比如,统计日志中每个ip地址出现了多少次,我们就可以利用数组去统计。

在awk中当变量的值为字符串时,也可以进行加法运算,如果字符串参与运算,字符串将被当做数字0进行运算,如:

1
2
3
awk 'BEGIN{a="test",print a;a=a+1;print a;a++;print a}'
1
2

当我们直接引用一个数组中不存在的元素时,awk会自动创建一个元素,并且为其赋值为”空字符串”。

1
2
awk 'BEGIN{pirnt testartt["ip"];testarr["ip"]++;print testarr["ip"]}'
2

当引用一个不存在的的元素时,元素被赋值为空字符串,当对这个元素进行自动运算时,元素的值就变成了1,因为,空字符串在参与运算时,被当做0使用了,所以,综上所述,我们对一个不存在的元素进行自加运算后,这个元素的值就变成了自加运算的次数,自加x次,元素的值就被赋值为x,自加y次,元素的值就被赋值为y.如:

1
2
awk 'BEGIN{print testarr["ip"];testarr["ip"]++;testarr["ip"]++;print testarr["ip"]}'
2

如统计次数常用:

1
awk '{a[$2]++}END{for(i in a){print i,a[i]}}' 文件名

上面我们使用一个空模式,一个END模式。

空模式中,我们随便创建一个数组,并且将ip地址作为引用元素的下标,进行了引用,如果这个元素并不存在,它会被空模式中的动作处理完毕后,a[“198.168.1.1”]的值会被赋值为1.

由于END模式中的动作会最后执行,所以我们可以先不考虑END模式。

这时,空模式中的动作继续处理下一行。

当遇到相同的ip地址时,使用同样一个ip地址作为下标的元素将会再次被自加,每次遇到相同的ip地址,对应元素的值都会加1

直到处理完所有行,开始执行END模式中的动作。

而END模式中,我们打印出a数组中的所有元素的下标,以及元素对应的值。

此刻,a的数组中的下标即为ip地址,元素的值即为对应ip地址出现的次数。

最终就统计出每个ip地址出现的次数。

总结:

我们对一个不存在的元素进行自加运算后,这个元素的值就变成了自加运算的次数。