曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 6763|回复: 2
打印 上一主题 下一主题

数组

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
跳转到指定楼层
楼主
发表于 2011-9-23 14:22:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
awk 中使用的数组时 “关联数组”(associative arays),该类型数组的下标可以数字也可以时字符串,但不论何种形式,下标通常都统称为键(key)。键和值都存储在 awk 内部的一个表中,存储方式采用哈希算法,因此数组元素不是顺序存储的。

在需要用时才创建数组,无需事先声明。根据使用时的上下文环境,数组元素被初始化为 0 或空的字符串。

示例一
root@bt:~# awk -F: '{name[x++]=$1}; END {for(i = 0; i < NR; i++) print i, name}' /etc/passwd
0 root
1 daemon
2 bin
3 sys
/* ... 省略一部分输出 ... */

30 festival
31 postgres
32 vboxadd



在上面的命令里创建了一个数组 name ,该数组用来存储 /etc/passwd 中的第一列的内容(用户名)。name 的下标为 x ,该变量由我们自定义,++ 运算符表示这是个数值型变量,而不是字符串型(这就是上下文),且 x 会被初始化为 0 ,在每处理一行后 x 会自动加 1 。END 块使用 for 循环来打印数组中的元素,其中 NR 时内置变量,保存了当前记录的记录号。

对于连续的数字作为下标时我们可以像上面那样用 for 来遍历数组,但如果下标为字符串或非连续的数字时我们不能这样使用,必须换另一种用法。此时 for 循环把下标作为键来查找与之关联的值(散列法的体现)。特殊 for 循环的格式为:
{ for (item in arrayname) {
    print arrayname[item]
   }
}


比如有一个文本里存放着一列人名(name.txt),其内容如下:
York
Tom
Jasmine
Jason
Jimy
Molly
Jasmine
Lili
LinKen
Cuki
Gaby
Jasmine
Gilbert
Gilber
Jasmine
使用下面的命令处理该文本,此举希望找到并打印出所有叫 Jasmine 的名字 :
# awk '/Jasmine/{name[NR]=$1}; END {for (i = 1; i <= NR; i++)print i, name}' name.txt
1
2
3 Jasmine
4
5
6
7 Jasmine
8
9
10
11
12 Jasmine
13
14
15 Jasmine
在上面的命令中,如果找到匹配模式 /Jasmine/ 的行,就为数组 name 赋一个值,其中使用 NR (当前记录号,也即当前处理到哪一行) 作为 name 的索引。所以当处理完文本后,数组中仅含有name[3], name[7], name[12], name[15] ,因此当使用 for 循环打印 name 时,除了 3, 7, 12, 15 外,其它的索引都是空的。


下面使用特殊 for 来遍历数组,这种方法将只打印有相应下标的元素的值。打印结果的次序是随机的,因为关联数组时以散列方式存储的:
# awk '/Jasmine/{name[NR]=$1}; END {for(i in name)print i, name}' name.txt
7 Jasmine
12 Jasmine
15 Jasmine
3 Jasmine
  
使用字符串作为数组
数组下标可以由单个字符或字符串变量组成,如果是字符串,则必须用双引号引起来。

假设有一个文本(name.txt)内容如下:
York
Tom
Jasmine
Jason
York
Jimy
Molly
Jasmine
Jason
Lili
LinKen
Cuki
Gaby
Jasmine
Gilbert
Gilber
Jasmine
Jason
Tom
Kiki
York
使用下面语句统计 Tom 和 Jasmine 这两个名字的出现次数:
# awk '/Tom/ {count["Tom"]++}; /Jasmine/ {count["Jasmine"]++};END {for (name in count)print name, count[name]}' name.txt
Tom 2
Jasmine 4
上面,数组 count 有两个元素:count["Tome"] 和 count["Jasmine"] 。这两个元素的初值都为 0,每次匹配时,count["Tom"] 和 count["Jasmine"] 的值都会加 1 。最后在 END 模式里打印出最终的统计结果。

我们还可以使用字段的值作为数组的下标:
# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
SYN_RECV 101
CLOSE_WAIT 3
ESTABLISHED 86
FIN_WAIT1 130
FIN_WAIT2 28
CLOSING 66
TIME_WAIT 2746
上面 NF 表示当前记录的字段数,而 $NF 则表示该字段上的值。该命令的具体含义可参考:http://www.groad.net/bbs/read.php?tid-4803.html

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
沙发
 楼主| 发表于 2011-9-23 15:43:12 | 只看该作者

split 和 delete 函数

split 是内置函数,它能够将字符串按照你所给出的分隔符拆分成单词,然后将它们保存到数组中。

split 函数有两种调用形式:
split (字符串, 数组, 字段分隔符)
split (字符串, 数组)

使用示例:
# awk 'BEGIN{split("23/9/2011", date, "/"); for(i = 1; i <= 3; i++) print date}'
23
9
2011
或者:
# awk 'BEGIN{split("23/9/2011", date, "/"); for(i in date) print date}'
23
9
2011
如果在 split 函数中不指定分隔符,那默认就以 FS 作为分隔符。

delete 也是内置函数,它用来删除数组元素。比如:
# awk 'BEGIN{split("23/9/2011", date, "/"); delete date[2]; for(i in date) print date}'
23
2011
注意 delete 函数的使用格式。在一些老的教材或书上,可能会将 delete 函数写成 delete(date[2]) 这种形式,即将数组元素用括号括起来,在新的 awk 里,这种格式是一种语法错误。要删除某个数组元素直接写成 delete 数组元素 即可。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
板凳
 楼主| 发表于 2011-9-23 16:24:59 | 只看该作者

多维数组

awk 也提供了定义多维数组的方法。该方法是,将多个下标串成字符串,下标之间用内置变量 SUBSEP 的值(该值为 \\034 ,是一个不可打印字符,极少被使用)分隔。比如 matrix[2, 8] 其实就等效于 matrix[2 SUBSEP 8],转换后得 matrix["2\\0348"] 。一般情况下,也不用去关心这个 SUBSEP 。

假设有下面一个文本(mularray.txt):
1 2 3 4 5
6 7 8 9 10
11 22 13 14 15
16 17 18 19 20
21 22 23 24 25

运行下面命令将文本中的各个数读入一个二维数组中,然后依次打印出来。脚本命令写在一个脚本文件中,如下所示:
[Bash shell] 纯文本查看 复制代码
{
        nf = NF
        for (x = 1; x <= NF; x++) {
                 matrix[NR, x] = $x
        }
}
END { for (x = 1; x <= NR; x++) {
                for (y = 1; y <= nf; y++)
                        printf "%d ", matrix[x,y]
                printf "\\n"
        }
    }


运行输出:
# awk -f mularr.awk mularray.txt
1 2 3 4 5
6 7 8 9 10
11 22 13 14 15
16 17 18 19 20
21 22 23 24 25
上面脚本的意思是:
在 END 之前,使用一个 for 循环读入文本中的数值到数组中。其中 NF 为当前记录的字段数,文本中一共有 5 列数字,那么这里 NF 的值就为 5 。NR 表示当前的记录数。for 循环一共进行了 5 次,读入文本顺序是 : 第 1 列数字($1) 读入到 matrix[1,1] (x 等于 1,NR 等于 1)中;第 2 列数字($2)复制到 matrix[2,2] (x 等于 2,NR 等于 2)中,以此类推。

在 END 后,因为是 2 维数组,所以用了两个 for 循环遍历了整个数组。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-6-17 21:45 , Processed in 0.067960 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表