awk数组简介

来源:互联网 发布:迅龙数据恢复软件 免费 编辑:程序博客网 时间:2024/06/05 17:14

from:http://techbbs.zol.com.cn/1/60_305.html

数组是一个包含一系列元素的表。数组的元素通过下标区分。下标可以是数字也可以是字符串。这个主节点描述了在awk 中数组如何工作、如何使用数组的元素、如何遍历数组每个元素、如何移除某个元素等内容。同时,描述了 awk 如何模拟多维数组和一些不常见的数组应用。并且,这个节点讲述了 gawk 如何根据数据的下标对数据进行排序。

Awk 在同一个命名空间里维护变量、数组和函数的名字,因此在一个 awk 程序里不允许变量和数组重名。

1 数组介绍

Awk 语言支持一维数组用于存放一组相关的字符串或者数字。每一个数组必需有一个名字。数组的命名与变量的命名遵守相同的惯例和约束。

Awk 的数组和其他编程语言的数组概念看上去类似。但是确有基本的不同。主要有两点

1、 awk 中的数组在使用一个数组之前不需要制定数组的大小( size )。

2、 任何数字或者字符串都可以作为数组的下标,而不仅仅是连续的整数。

 

在大部分的编程语言中,数组必需先定义,包括包含多少个元素(也就是数组的大小),然后才能使用。在这些语言中,数组的定义将使系统分配连续的内存 块给数组的元素。通常,这些数组的下标必需是正整数。例如,下标 0 指向数组的第一个元素,存在内存块的最前端。下标 1 指向数组的第二个元素,在内存块中紧挨第一个元素之后保存。不可以添加元素到数组,因为数组在定义的时候已经指定了空间的大小。(一些语言允许用户任意指定下标的起始值和结束值,例如15..27 ,但是数组的大小还是固定的)。

一个具有四个元素的连续数组通常如下:

8

foo

“”

30

下标

0

1

2

3

 

在 awk 中,数组是关联数组,它的特点是:

1、 数组的下标可以是整数,也可以是负数甚至是字符串

2、 数组的下标可以不连续。

Awk 的变量 IGNORECASE 的值不影响数组下标。

当 awk 创建一个数组的时候,如果没有指定下标,默认已连续整数作为下标,起始值是 1.

Awk 的数组是什么高效的,访问一个元素的时间跟元素的数量无关。

注: awk 的下标其实都是字符串,如我们输入的是数字 1 , awk 会自动的转换为字符串“ 1 ”。

 

 

2 引用元素

引用 awk 元素的基本方法是:

ARRAY[INDEX]


注: 在此引用方式中除非 [ ] 中写的是变量,否则需要添加双引号,即字符串必需添加双引号的规则在数组的下标中也必需遵守,但如果下标是全数字,则可以不加引号,例:

Bb=”123”

arr[bb] awk 将 bb 认作变量,获取的是 arr[“123”] 的值

arr[234] awk 将 234 认作字符串,虽然 234 没加引号。因为变量的定义不能用全数字,所以 234 肯定是字符串,而不是变量。

arr[ bb ] awk 将 bb 认作字符串,获取的是 arr[“bb”] 的值

 

有时候,数组的 value 会为空。 value 为空的元素包含两种情况, 1 、本身 value 为空。 2 、通过 delete 删除后的元素。这两种情况都可以被正常引用。但不幸的是,如果引用了一个不存在的元素,会导致 awk 创建这个元素, value 为空,这样,会导致 awk 的内存浪费。

如果要查询具有某个 index 值的元素是否存在可以用如下的表达式:

INDEX in ARRAY

 

 

 

这个表达式仅仅测试具有 INDEX 的元素在 ARRAY 中是否存在。如果不存在,该表达式不会导致产生以 INDEX 为下标的 value 为空的元素。

如果元素存在,该表达式返回值  true 

反之,返回  false 

例:测试在数组 frequencies 中是否存在下标为 2 的元素

. if (2 in frequencies)

print “Sub 2 is present.”

 

 

注: 不能测试 frequencies 中是否存在 value 为 2 的元素,除非 scan 数组中的所有元素。

 

3 给元素赋值

给 awk 的数组赋值,只能采用如下形式:

ARRAY[SUB] = VALUE

 

ARRAY :数组名字

SUB :下标

VALUE :值

4 数组实例

 

 

以下文件以数字为行首

5 I am the Five man

2 Who are you? The new number two!

4 . . . And four on the floor

1 Who is number one?

3 I three you.

以下的 awk 程序将以上文件,按行首的数字顺序逐行打印:

{

if ($1 > max)

max = $1

arr[$1] = $0

}

END {

for (x = 1; x <= max; x++)

print arr[x]

}

 

程序第一部分实现两个功能:

1、 得到行首数字的最大值

2、 已行首数字为下标,将相应的行存入数组

程序执行完毕输出结果如下:

1 Who is number one?

2 Who are you? The new number two!

3 I three you.

4 . . . And four on the floor

5 I am the Five man

如果行首数字有相重的情况,后面的行将覆盖前面的行,前面的行不会打印出来。

如果有行首数字为空的情况,可以用以下的增强方式予以处理:

END {

for (x = 1; x <= max; x++)

if (x in arr)

print arr[x]

}

注: awk 可以生成下标为空的元素,但是引用方式必需是 arr[ “” ], 而不是 arr[]

5 遍历数组

在使用数组的程序里,经常会使用一个循环让数组里的每一个元素都执行一次某一个操作。在其他程序里,数组的下标是连续的正整数,因此所有的下标很容易通过从低到高实现遍历。但这个方法在 awk 里不能使用,因为 awk 的下标可以是数字也可以是字符串。因此, awk 使用一种特别的语句来遍历数组里的元素:

for (VAR in ARRAY)

BODY

以上的循环将实现让数组 ARRAY 里的每一个元素都执行一次 BODY 。

以下程序的第一部分,将输入文本的每一个单词都作为下标存放入数组,如单词有重复,仅仅保留一个,因数组的下标是不能重复的。

程序的第二部分,将这些单词判断是否大于 10 个字母。如是,打印出来,并将计数器 +1 。最后打印出输入文件中有多少个单词超过 10 个字母。

#!/bin/awk

{

for (i = 1; i <= NF; i++)

used[$i] = 1

}

END {

for (x in used)

if (length(x) > 10) {

++num_long_words

print x

} print num_long_words, “words longer than 10 characters”

}

注: 1 、下标的输出顺序是 awk 使用内置规则排列的,不要试图在 for 循环内试图改变、控制这个顺序,否则会出现意料不到的后果。

2 、同样,在 for 循环内不要更改 VAR 的值,在上例就是在黄色区域内,不要更改 x 的值,否则,同样会出现意料不到的后果。

6 删除元素

删除单个元素

delete ARRAY[INDEX]

删除整个数组方法 1

for (VAR in ARRAY)

delete ARRAY[VAR]

删除整个数组方法 2 (该方法 gawk 专用,可移植性差,但效率是方法 1 的 3 倍左右)

delete ARRAY

删除整个数组方法 3( 该方法具移植性,但其实是一种变通的方法,就如同医药里的偏方。 Split 试图分割一个 null string ,发现没有可分割和输出的,于是它简单的 clear 了数组 ARRAY)

split(”", ARRAY)

 

 

一个元素被删除和给他赋空值是不同的,所以以下两端代码结果也截然不同:

delete foo[4]

if (4 in foo)

print “This will never be printed”

结果:不会打印“ This will never be printed ”

foo[4] = “”

if (4 in foo)

print “This is printed, even though foo[4] is empty”

结果:会打印“ This is printed, even though foo[4] is empty ”

 

Awk 的数组和变量用的是同一个地址空间,数组的名字和变量不能重名。即使数组删除了也不能将名字用于变量命名,以下命令会报错:

a[1] = 3; delete a; a = 3

 

 

 



7 数字下标

Awk 的数组下标都是字符串,如果输入的是数字, awk 会自动转换。 Awk 下标中的数字,受变量 CONVFMT 的影响。例:

xyz = 12.153

data[xyz] = 1

8.数组赋值

单个赋值: Tarray[1]=“cheng mo”  Tarray[2]=“800927”

多个赋值:awk 'BEGIN{info="it is a test";lens=split(info,tA," ");print length(tA),lens,tA[1];}'

4 4 it   #awk的数组下标从1开始的。

bash的多个赋值:a=(1 2 4)  ;echo ${a[2]}





0 0