awk程序中允许使用字符串当做数组的下标(index),这个特点有助于资料的统计。(使用字符串当下标的数组称为Associative Array)
首先建立一个名为kecheng.dat数据文件,内容是学生选课的内容;第一栏为学生姓名,其后为该生所学课程,内容如下:
[root@benet pub]# cat kecheng.dat
zhangsan math english chinese
lisi computer chinese english
wangwu dianzi chinese math
zhaoliu huanjing english chinese
awk中数组不需要声明,也不用指定数组的大小,直接使用字符串当数组的下标(index)。 以上边学生选课为数据文件统计一下kecheng.dat 中学习各门课程的人数。
这种情况,有二项信息必须储存: (a) 课程名称, 如:math,English,共有哪些课程事先并不明确。 (b)各课程的选修人数。 如: 有几个人选修了“math”。
在awk 中只用一个数组就可同时记录上述信息。 方法如下:使用数组Number[ ]:以课程名称当Number[ ]的下标。 以Number[ ] 中不同下标所对映的元素代表各门课程的人数。 例如:有2个学生学习“math”,则以Number["math"]=2表示。如果学习math的人数增加一人,则Number[“math”]=Number[“math”]+1 或Number[“math”]++ 将学习该门课程的人数加1。
那么如何读出数组中储存的信息呢?以math为例,声明int Arr[100]数组后,如果想显示数组中的数值,使用一个for循环就可以了,如:for(i=0; i<100; i++) printf(“%d/n”, Arr[i]); 即可。上式中:数组Arr[ ] 的下标 :0,1,2,…,99, 数组Arr[ ] 中各下标所对应的值:Arr[0],Arr[1],…,Arr[99]。
上面说了awk 中使用数组不须声明,以数组number[]为例,程序执行前,并不知有哪些课程名称可能被当成Number[ ]的下标。在awk中提供了一个指令,通过该指令awk会自动找寻数组中所有使用过的下标。以Number[ ] 为例,awk将会找到“math”,“english”,使用该指令时,只要首先指定要找寻的数组和变量即可,awk会记录从数组中找到的每一个下标。
例如:for(course in Number){…}
指定使用course 来记录awk 从Number[ ]中找到的下标,awk每找到一个下标,就用course记录该下标的值且执行{…}中的指令。
例子:统计kecheng.dat中每门课程有多少学生学习,并输出结果。
处理方法:建立使用awk编写的脚本程序,脚本的内容如下:
[root@benet pub]# cat course.awk
#!/bin/awk -f
BEGIN{
FS=” “}
{
for(i=2;i<=NF;i++){number[$i]++;}
}
END{
for(course in number)printf(“%10s %d/n”,course,number[course]);
}
在程序中需要注意,awk程序主要有三部分组成,BEGIN,中央处理部分和END三个部分,BEGIN和END是awk的保留字,后面必须是“{”,如果没有紧跟着“{”,执行程序的时候,会报错;FS是field separate的缩写,用来存储域分隔符。
执行结果如下:
[root@benet pub]# awk -f course.awk kecheng.dat
computer 1
english 3
dianzi 1
chinese 4
math 2
huanjing 1
程序解释:这程序包含三个Pattern { Actions }指令。
第一个Pattern { Actions }指令中的FS上面已经说过了,后面跟着分隔数据文件的分隔符,在这里,是以空格来进行分隔数据行的没一个部分的,所以FS=” “;如果是分隔/etc/passwd这个文件,那么FS=”:”,在以后分隔数据文件的时候,一定要选择正确的域分隔符,并用FS进行设置。
第二个Pattern { Actions }指令中省略了Pattern 部分,所以每行数据读入后,都会在Actions部分将逐次无条件执行。awk在读入第一行数据zhangsan math english chinese的时候,因为该行数据有NF=4个字段,所以Action 的for循环中i从2开始,因为第一个字段是学生的名字,不用进行统计;而其后的各个域需要统计,所以for循环中i取值为2,3,4。Number[$i]++ 这句中,在i=2时,$2是第二个域的值,即$2=math,Number[math]的值从默认的0,++变成了1 ; i=3时$i=english,Number[english]的值默认是0,++变成了1 ; 同理,i=4时 $i=chinese,Number[chinese]的值从默认的0,++后变成了1 ; 第一行数据处理完后,再次读入下一行,根据$i的内容,如果数组中没有,就会新添加一个课程,并将选择给课程的学生数加1,如果该课程在数组中已经存在,只将改课程的人数加1。
第三个Pattern{Actions}指令中END 为awk的保留字,而且必须是大写,是Pattern的一种。END 成立(其值为true)的条件是: “awk处理完所有数据,即将离开程序时”,平常读入数据行时,END并不成立,所以END后面的Actions 并不被执行;只有当awk读完所有数据时,Actions才会被执行。
BEGIN与END 有点类似,是awk 中另一个保留的Pattern。 唯一不同的是:“以BEGIN 为Pattern的Actions 在程序一开始的时候被执行一次”, NF 为awk 的内建变量,用来表示awk正在处理的数据行中所包含的字段的个数。
awk程序中以$开头的变量, 都是下面这种意思:以i= 2 为例,$i=$2 表示第二个字段数据(实际上,$在awk 中 为一运算符(Operator),用以取得字段数据)。