windows ubuntu sed,awk,grep篇:12.awk 关联数组

目录

[78. 引用数组元素](#78. 引用数组元素)

[79.使用循环遍历 awk 数组](#79.使用循环遍历 awk 数组)

[80. 删除数组元素](#80. 删除数组元素)

[81. 多维数组](#81. 多维数组)

[82. SUBSEP 下标分隔符](#82. SUBSEP 下标分隔符)

[83. 用 asort 为数组排序](#83. 用 asort 为数组排序)

[84. 用 asorti 为索引排序](#84. 用 asorti 为索引排序)


相比较与其他编程语言中的传统数组, awk 的数组更为强大。
Awk 的数组,都是关联数组,即一个数组包含多个 " 索引 / 值 " 的元素。索引没必要是一系列
连续的数字,实际上,它可以使字符串或者数字,并且不需要指定数组长度。
语法:
arrayname[string]=value
arrayname 是数组名称
string 是数组索引
value 是为数组元素赋的值
访问 awk 数组的元素
如果要访问数组中的某个特定元素,使用 arrayname[index] 即可返回该索引中的值。
一个简单的数组赋值示例 :
$ cat array-assign.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 item["101"];
print item[102];
print item["103"];
print item[104];
print item["105"];
print item[1001];
print item["na"];
}
$ awk -f array-assign.awk
HD Camcorder
Refrigerator
MP3 Player
Tennis Racket
Laser Printer
Tennis Ball
Not Available
请注意 :
数组索引没有顺序,甚至没有从 0 或 1 开始,而是直接从 101....105 开始 , 然后直接
跳到 1001 ,又降到 55 ,还有一个字符串索引 "na".
数组索引可以是字符串,数组的最后一个元素就是字符串索引,即 "na"
Awk 中在使用数组前,不需要初始化甚至定义数组,也不需要指定数组的长度。
Awk 数组的命名规范和 awk 变量命名规范相同。 以 awk 的角度来说,数组的索引通常是字符串,即是你使用数组作为索引, awk 也会当
做字符串来处理。下面的写法是等价的:
Item[101]="HD Camcorder"
Item["101"]="HD Camcorder"

**78.**引用数组元素

如下所示,可以使用 print 命令直接打印数组的元素,也可以把元素的值赋给其他变量以便
后续使用。
print item[101]
x=item[105]
如果视图访问一个不存在的数组元素, awk 会自动以访问时指定的索引建立该元素,并赋予
null 值。为了避免这种情况,在使用前最后检测元素是否存在。
使用 if 语句可以检测元素是否存在,如果返回 true,说明改元素存在于数组中。
if ( index in array-name )
一个简单的引用数组元素的例子 :
$ cat array-refer.awk
BEGIN {
x = item[55];
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 )
print "Array index 1010 contains",item[1010];
}
$ awk -f array-refer.awk
Array index 55 contains
Array index 101 contains HD Camcorder
该例中:
z Item[55] 在引用前没有赋任何值,所以在引用是 awk 自动创建该元素并赋 null 值
z Item[101] 是一个已赋值的缘分,所以在检查索引值时返回 true ,打印该元素
z Item[1010] 不存在,因此检查索引值时,返回 false ,不会被打印

79.使用循环遍历awk****数组

如果要访问数组中的所有元素,可以使用 for 的一个特殊用法来遍历数组的所有索引: 语法:
for ( var in arrayname )
actions
其中 :
var 是变量名称
in 是关键字
arrayname 是数组名
actions 是一系列要执行的 awk 语句,如果有多条语句,必须包含在 { } 中。通过把
索引值赋给变量 var ,循环体可以把所有语句应用到数组中所有的元素上。
在示例 "for (x in item)" 中, x 是变量名,用来存放数组索引。
请注意,我们并没有指定循环执行的条件,实际上我们不比关系数组中有多少个元素,因为
awk 会自动判断,在循环结束前遍历所有元素。
下面的例子遍历数组中所有元素并打印出来。
$ cat array-for-loop.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)
print item[x]
}
$ awk -f array-for-loop.awk
Not Available
Laptop
HD Camcorder
Refrigerator
MP3 Player
Tennis Racket
Laser Printer
Tennis Ball

**80.**删除数组元素

如果要删除特定的数组元素,使用 delete 语句。一旦删除了某个元素,就再也获取不到它
的值了。
语法:
delete arrayname[index];
删除数组内所有元素
for (var in array)
delete array[var]
在 GAWK 中,可以使用单个 delete 命令来删除数组的所有元素 :
Delete array
此外,下面例子中 ,item[103]="" 并没有删除整个元素,仅仅是给它赋了 null 值。
$ cat array-delete.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";
delete item[102]
item[103]=""
delete item[104]
delete item[1001]
delete item["na"]
for(x in item)
print "Index",x,"contains",item[x]
}
$ awk -f array-delete.awk
Index no contains Not Available
Index 55 contains Laptop
Index 101 contains HD Camcorder
Index 103 contains
Index 105 contains Laser Printer

**81.**多维数组

虽然 awk 只支持一维数组,但其奇妙之处在于,可以使用一维数组来模拟多维数组。
假定要创建下面的 2X2 维数组 :
10 20
30 40 其中位于 "1,1" 的元素是 10 ,位于 "1,2" 的元素是 20 ,等等 ..., 下面把 10 赋值给 "1,1" 的元素 :
item["1,1"]=10
即使使用了 "1,1" 作为索引值,它也不是两个索引,仍然是单个字符串索引,值为 "1,1" 。所
以上面的写法中,实际上是把 10 赋给一维数组中索引 "1,1" 代表的值。
$ 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]
}
$ awk -f array-multi.awk
30
20
40
10
现在把索引外面的引号去掉,会发生什么情况?即 item[1,1]( 而不是 item["1,1"]):
$ 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]
}
$ awk -f array-multi2.awk
10
30
20
40
上面的例子仍然可以运行,但是结果有所不同。在多维数组中,如果没有把下标用引号引住,
awk 会使用 "\034" 作为下标分隔符。
当指定元素 item[1,2] 时,它会被转换为 item["1\0342"] 。 Awk 用把两个下标用 "\034" 连接起
来并转换为字符串。 当使用 ["1,2"] 时,则不会使用 "\034" ,它会被当做一维数组。
如下示例
$ cat array-multi3.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];
}
$ awk -f array-multi3.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"

82. SUBSEP****下标分隔符

通过变量 SUBSEP 可以把默认的下标分隔符改成任意字符,下面例子中, SUBSEP 被改成了分
号 :
$ cat array-multi4.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];
}
$ awk -f array-multi4.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 变量。
所以,使用多维数组时,最好不要给索引值加引号,如 :
$ cat array-multi5.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];
}
$ awk -f array-multi5.awk
Index 1:1 contains 10
Index 2:1 contains 30
Index 1:2 contains 20
Index 2:2 contains 40

83.asort****为数组排序

asort 函数重新为元素值排序,并且把索引重置为从 1 到 n 的值,此处 n 代表数组元素个数。
假定一个数组有两个元素 :item["something"]="B - I'm big b" 和 item["notsure"]="A -- I'm big a"
调用 asort 函数手,数组会以元素值排序,变成 :item[1]="A -- I'm big a" 和 item[2]="B -- I'm big
b"
下面例子中,数组索引是非连续的数字和字符串,调用 asort 后,元素值被排序,并且索引
值变成 1,2,3,4.... 请注意, asort 函数会返回数组元素的个数。
$ 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;
}
$ 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 -------------
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 ,而是随机的。可以用下面
的方法,按索引值顺序打印 :
$ 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++)
print "Index",i,"contains",item[i]
}
$ 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
或许你已经注意到,一旦调用 asort 函数,数组原始的索引值就不复存在了。因此,你可能
想在不改变原有数组索引的情况下,使用新的索引值创建一个新的数组。
下面的例子中,原始数组 item 不会被修改,相反,使用排序后的新索引值创建新数组 itemnew,
即 itemnew[1],itemnew[2],itemnew[3], 等等。
total = asort(item,itemnew);
再次申明,务必牢记 asort 函数按元素值排序 , 但排序后使用从 1 开始的新索引值,原先的索
引被覆盖掉了。

84.asorti****为索引排序

和以元素值排序相似,也可以取出所有索引值,排序,然后把他们保存在新数组中。
下面的例子展示了 asort 和 asorti 的不同 , 请牢记下面两点 :
asorti 函数为索引值 ( 不是元素值 ) 排序,并且把排序后的元素值当做元素值保存。
如果使用 asorti(state) 将会丢失原始元素值,即索引值变成了元素值。因此为了保
险起见,通常给 asorti 传递两个参数,即 asorti(state,statebbr). 这样一来,原始数组
state 就不会被覆盖了。
$ 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];
}
$ 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
资料来源于《SedandAwk101Hacks》,大家有兴趣可以买一本,也可以关注我,我更新完它。

曾经,我花费大半月将它们跑完,现在啥都忘了,还是要常用。

只为学习交流,不为获利,侵权联系立删。

相关推荐
C++忠实粉丝28 分钟前
Linux环境基础开发工具使用(2)
linux·运维·服务器
天上掉下来个程小白29 分钟前
Stream流的中间方法
java·开发语言·windows
暮雪倾风35 分钟前
【WPF开发】控件介绍-Grid(网格布局)
windows·wpf
康熙38bdc1 小时前
Linux 环境变量
linux·运维·服务器
hakesashou2 小时前
python如何比较字符串
linux·开发语言·python
Ljubim.te2 小时前
Linux基于CentOS学习【进程状态】【进程优先级】【调度与切换】【进程挂起】【进程饥饿】
linux·学习·centos
cooldream20092 小时前
Linux性能调优技巧
linux
sukalot2 小时前
windows C++-windows C++-使用任务和 XML HTTP 请求进行连接(二)
c++·windows
QMCY_jason3 小时前
Ubuntu 安装RUST
linux·ubuntu·rust
慕雪华年3 小时前
【WSL】wsl中ubuntu无法通过useradd添加用户
linux·ubuntu·elasticsearch