Awk 的数组,都是关联数组,即一个数组包含多个”索引/值”的元素。 索引没必要是一系列 连续的数字,实际上,它可以使字符串或者数字,并且不需要指定数组长度。
语法:
arrayname[string]=value
-
arrayname 是数组名称
-
string 是数组索引
-
value 是为数组元素赋的值
访问 awk 数组的元素
如果要访问数组中的某个特定元素,使用 arrayname[index] 即可返回该索引中的值。
实例1:
[root@localhost ~]# awk ' >BEGIN{ item[101]="HD Camcorder"; >item["102"]="Refrigerator"; >item[103]="MP3 Player"; >item["na"]="Young" >print item[101]; >print item["102"]; #注意带引号不带引号awk都视为字符串来处理 >print item[103]; >print item["na"];}' #字符串索引需要加双引号 HD Camcorder Refrigerator MP3 Player Young
注意:
-
数组索引没有顺序,甚至没有从 0 或 1 开始.
-
数组索引可以是字符串,数组的最后一个元素就是字符串索引,即”na”
-
Awk 中在使用数组前,不需要初始化甚至定义数组,也不需要指定数组的长度。
-
Awk 数组的命名规范和 awk 变量命名规范相同。
以 awk 的角度来说,数组的索引通常是字符串,即是你使用数组作为索引, awk 也会当 做字符串来处理。下面的写法是等价的:
Item[101]="HD Camcorder" Item["101"]="HD Camcorder"
一、引用数组元素
如果试图访问一个不存在的数组元素, awk 会自动以访问时指定的索引建立该元素,并赋予 null 值。 为了避免这种情况,在使用前最后检测元素是否存在。
使用 if 语句可以检测元素是否存在,如果返回 true,说明改元素存在于数组中。
if ( index in array-name )
实例2:一个简单的引用数组元素的例子
[root@localhost ~]# cat arr.awk BEGIN { x = item[55]; #在引用前没有赋任何值,所以在引用是 awk 自动创建该元素并赋 null 值 if ( 55 in item ) print "Array index 55 contains",item[55]; item[101]="HD Camcorder"; if ( 101 in item ) print "Array index 101 contains",item[101]; if ( 1010 in item ) #不存在,因此检查索引值时,返回 false,不会被打印 print "Array index 1010 contains",item[1010]; } [root@localhost ~]# awk -f arr.awk Array index 55 contains Array index 101 contains HD Camcorder
二、使用循环遍历 awk 数组
如果要访问数组中的所有元素, 可以使用 for 的一个特殊用法来遍历数组的所有索引:
语法:
for ( var in arrayname ) actions
说明:
-
var 是变量名称
-
in 是关键字
-
arrayname 是数组名
-
actions 是一系列要执行的 awk 语句,如果有多条语句,必须包含在{ }中。 通过把索引值赋给变量 var,循环体可以把所有语句应用到数组中所有的元素上。
实例1:将数组中元素全部打印出来
[root@localhost ~]# cat arr-for.awk BEGIN { item[101]="HD Camcorder"; item[102]="Refrigerator"; item[103]="MP3 Player"; item[104]="Tennis Racket"; item[105]="Laser Printer"; item[1001]="Tennis Ball"; item[55]="Laptop"; item["no"]="Not Available"; for(x in item) #x 是变量名,用来存放数组索引,无需制定条件,awk自行判断 print item[x]; } [root@localhost ~]# awk -f arr-for.awk Not Available Laptop HD Camcorder Refrigerator MP3 Player Tennis Racket Laser Printer Tennis Ball
三、删除数组元素
如果要删除特定的数组元素,使用 delete 语句。一旦删除了某个元素,就再也获取不到它 的值了。
语法:
delete arrayname[index];
删除数组内所有元素:
for (var in array) delete array[var]
在 GAWK 中,可以使用单个 delete 命令来删除数组的所有元素:
Delete array
实例1:
[root@localhost ~]# awk ' >BEGIN{item[101]="HD Camcorder"; >item[102]="Refrigerator"; >item[103]="MP3 Player"; >delete item[101]; >print item[101];print item[102]; >for(x in item) delete item[x]; #使用for循环删除全部数组 >print item[102];print item[103];}' Refrigerator [root@localhost ~]#
实例2���
[root@localhost ~]# awk ' >BEGIN{item[1]="a"; >item[2]="b";item[3]="c"; >delete item; #使用delete直接加数组名称删除全部数组 >for(x in item) print item[x];}'
四、多维数组
虽然 awk 只支持一维数组,但可以使用一维数组来模拟多维数组。
实例1:
[root@localhost ~]# cat array-multi.awk BEGIN { item["1,1"]=10; item["1,2"]=20; item["2,1"]=30; item["2,2"]=40 for (x in item) print item[x] } [root@localhost ~]# awk -f array-multi.awk 30 20 40 10
说明:即使使用了”1,1”作为索引值,它也不是两个索引,仍然是单个字符串索引,值为”1,1”。所 以item[“1,1”]=10
,实际上是把 10 赋给一维数组中索引”1,1”代表的值。
实例2:将双引号去掉
[root@localhost ~]# cat array-multi2.awk BEGIN { item[1,1]=10; item[1,2]=20; item[2,1]=30; item[2,2]=40 for (x in item) print item[x] } [root@localhost ~]# awk -f array-multi2.awk 10 30 20 40
说明:上面的例子仍然可以运行,但是结果有所不同。在多维数组中,如果没有把下标用引号引住, awk 会使用”\034”作为下标分隔符。
当指定元素 item[1,2]时,它会被转换为 item[“1\0342”]。 Awk 用把两个下标用”\034”连接起 来并转换为字符串。
实例3:
[root@localhost ~]# cat 034.awk BEGIN { item["1,1"]=10; item["1,2"]=20; item[2,1]=30; item[2,2]=40; for(x in item) print "Index",x,"contains",item[x]; } [root@localhost ~]# awk -f 034.awk Index 1,2 contains 20 Index 21 contains 30 Index 22 contains 40 Index 1,1 contains 10
说明:
索引”1,1”和”1,2”放在了引号中,所以被当做一维数组索引, awk 没有使用下标分 隔符,因此,索引值被原封不动地输出。
所以 2,1 和 2,2 没有放在引号中,所以被当做多维数组索引, awk 使用下标分隔符 来处理,因此索引变成”2\0341”和”2\0342”,于是在两个下标直接输出了非打印字符 “\034”
五、SUBSEP 下标分隔符
通过变量 SUBSEP 可以把默认的下标分隔符改成任意字符。
实例1:
[root@localhost ~]# cat subsep.awk BEGIN { SUBSEP=":"; item["1,1"]=10; item["1,2"]=20; item[2,1]=30; item[2,2]=40; for(x in item) print "Index",x,"contains",item[x]; } [root@localhost ~]# awk -f subsep.awk Index 1,2 contains 20 Index 2:1 contains 30 Index 2:2 contains 40 Index 1,1 contains 10
说明:索引”1,1”和”1,2”由于放在了引号中而没有使用 SUBSEP 变量。
注意:使用多维数组时,最好不要给索引值加引号,直接使用SUBSEP变量制定索引分隔符。
六、用 asort 为数组排序
asort 函数重新为元素值排序,并且把索引重置为从 1 到 n 的值,此处 n 代表数组元素个数。
实例1:
[root@localhost ~]# cat asort.awk BEGIN { item[101]="HD Camcorder"; item[102]="Refrigerator";item[103]="MP3 Player"; item[104]="Tennis Racket"; item[105]="Laser Printer"; item[1001]="Tennis Ball"; item[55]="Laptop"; item["na"]="Not Available"; print "---------- Before asort -------------" for(x in item) print "Index",x,"contains",item[x] total = asort(item); print "---------- After asort -------------" for(x in item) print "Index",x,"contains",item[x] print "Return value from asort:",total; } [root@localhost ~]# awk -f asort.awk ---------- Before asort ------------- Index 55 contains Laptop Index 101 contains HD Camcorder Index 102 contains Refrigerator Index 103 contains MP3 Player Index 104 contains Tennis Racket Index 105 contains Laser Printer Index na contains Not Available Index 1001 contains Tennis Ball ---------- After asort ------------- #awk数组索引是从1开始的不是0 Index 4 contains MP3 Player Index 5 contains Not Available Index 6 contains Refrigerator Index 7 contains Tennis Ball Index 8 contains Tennis Racket Index 1 contains HD Camcorder Index 2 contains Laptop Index 3 contains Laser Printer Return value from asort: 8
注意:一旦调用 asort 函数,数组原始的索引值就不复存在了,索引并不是按照1-8排序而是随机排序。
实例2:增加索引排序功能
[root@localhost ~] cat asort1.awk BEGIN { item[101]="HD Camcorder"; item[102]="Refrigerator";item[103]="MP3 Player"; item[104]="Tennis Racket"; item[105]="Laser Printer"; item[1001]="Tennis Ball"; item[55]="Laptop"; item["na"]="Not Available"; total = asort(item); for(i=1;i<=total;i++) #添加for循环控制索引输出的顺序 print "Index",i,"contains",item[i] } [root@localhost ~] awk -f asort1.awk Index 1 contains HD Camcorder Index 2 contains Laptop Index 3 contains Laser Printer Index 4 contains MP3 Player Index 5 contains Not Available Index 6 contains Refrigerator Index 7 contains Tennis Ball Index 8 contains Tennis Racket
七、用 asorti 为索引排序
和以元素值排序相似,也可以取出所有索引值,排序,然后把他们保存在新数组中。
说明:
-
asorti 函数为索引值(不是元素值)排序,并且把排序后的元素值当做元素值保存。
-
如果使用 asorti(state)将会丢失原始元素值,即索引值变成了元素值。因此为了保险起见,通常给 asorti 传递两个参数,即 asorti(state,statebbr).这样一来,原始数组state 就不会被覆盖了。
实例1:
[root@localhost ~]# cat asorti.awk BEGIN { state["TX"]="Texas"; state["PA"]="Pennsylvania"; state["NV"]="Nevada"; state["CA"]="California"; state["AL"]="Alabama"; print "-------------- Function: asort -----------------" total = asort(state,statedesc); for(i=1;i<=total;i++) print "Index",i,"contains",statedesc[i]; print "-------------- Function: asorti -----------------" total = asorti(state,stateabbr); for(i=1;i<=total;i++) #索引按顺序输出也需要自行排序 print "Index",i,"contains",stateabbr[i]; } [root@localhost ~]# awk -f asorti.awk -------------- Function: asort ----------------- Index 1 contains Alabama Index 2 contains California Index 3 contains Nevada Index 4 contains Pennsylvania Index 5 contains Texas -------------- Function: asorti ----------------- Index 1 contains AL Index 2 contains CA Index 3 contains NV Index 4 contains PA Index 5 contains TX
补充实例:利用数组删除重复行
[root@localhost ~]
# cat alpha
a
a
a
b
c
b
d
d
e
e
f
f
f
f
g
[root@localhost ~]
# awk '!a[$0]++' alpha
a
b
c
d
e
f
g
注解:
为何上面的命令将重复的行去掉了呢?原因如下:首先,当读入第一个字符a时,关联数组array的以a为索引的值为空,即array[a]=0,将此取反为1,逻辑上为真,则输出第一行,然后自相加为2。其次,当读入第二个值b时,同理可知为1,array也为1。当第二次读入a时,因为array[a]的值已经为2,(逻辑)取反之后为0,逻辑上是假,则不会输出,自相加最后为1。
注意:第一点,!的运算顺序比++要更优先;第二点,++是在print之后才会执行。
本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-02/140276.htm