awk中记录、循环与数组入门教程,awk中多行记录,awk循环结构,awk数组工具等用法。
本节重点: 1、多行记录 awk是一种用于读取和处理结构化数据(如系统的/etc/passwd文件)的极佳工具。/etc/passwd是UNIX用户数据库,并且是用冒号定界的文本文件,它包含许多重要信息,包括所有现有用户帐户和用户标识,以及其它信息。在我的前一篇文章中,我演示了awk如何轻松地分析这个文件。我们只须将FS(字段分隔符)变量设置成":"。 正确设置了FS变量之后,就可以将awk配置成分析几乎任何类型的结构化数据,只要这些数据是每行一个记录。然而,如果要分析占据多行的记录,仅仅依靠设置FS是不够的。在这些情况下,还需要修改RS记录分隔符变量。RS变量告诉awk当前记录什么时候结束,新记录什么时候开始。 譬如,如何完成处理“联邦证人保护计划”所涉及人员的地址列表的任务: 代码 1.1: “联邦证人保护计划”所涉及人员的地址列表
Jimmy the Weasel
Big Tony
理论上,希望awk将每3行看作是一个独立的记录,而不是三个独立的记录。
代码 1.2: 从地址新建一个字段
BEGIN {
FS="\n" RS="" } 在上面这段代码中,将FS设置成"\n"告诉awk每个字段都占据一行。通过将RS设置成"",还会告诉awk每个地址记录都由空白行分隔。一旦awk知道是如何格式化输入的,它就可以为我们执行所有分析工作,脚本的其余部分很简单。让我们研究一个完整的脚本,它将分析这个地址列表,并将每个记录打印在一行上,用逗号分隔每个字段。
代码 1.3: 完整的脚本
BEGIN {
FS="\n" RS="" } { print $1 ", " $2 ", " $3 } 如果这个脚本保存为address.awk,地址数据存储在文件address.txt 中,可以通过输入"awk -f address.awk address.txt"来执行这个脚本。此代码将产生以下输出:
代码 1.4: 脚本输出 在address.awk的print语句中,可以看到awk会连接(合并)一行中彼此相邻的字符串。我们使用此功能在同一行上的三个字段之间插入一个逗号和空格(", ")。这个方法虽然有用,但比较难看。与其在字段间插入","字符串,倒不如让通过设置一个特殊awk变量OFS,让awk完成这件事。请参考下面这个代码片断。 代码 1.5:
print "Hello", "there", "Jim!"
代码 1.6: awk产生的输出
代码 1.7: 重新定义OFS
BEGIN {
FS="\n" RS="" OFS=", " } { print $1, $2, $3 } awk还有一个特殊变量ORS,全称是“输出记录分隔符”。通过设置缺省为换行 ("\n") 的OFS,我们可以控制在print语句结尾自动打印的字符。缺省ORS值会使awk在新行中输出每个新的print语句。如果想使输出的间隔翻倍,可以将ORS设置成"\n\n"。或者,如果想要用单个空格分隔记录(而不换行),将ORS设置成""。 将多行转换成用tab分隔的格式 假设我们编写了一个脚本,它将地址列表转换成每个记录一行,且用tab定界的格式,以便导入电子表格。使用稍加修改的address.awk之后,就可以清楚地看到这个程序只适合于三行的地址。如果awk遇到以下地址,将丢掉第四行,并且不打印该行:
代码 1.8: Sample entry
代码 1.9: 改进后的代码
BEGIN {
FS="\n" RS="" ORS="" } { x=1 while ( x<NF ) { print $x "\t" x++ } print $NF "\n" } 首先,将字段分隔符FS设置成"\n",将记录分隔符RS设置成"",这样awk可以象以前一样正确分析多行地址。然后,将输出记录分隔符ORS设置成"",它将使print语句在每个调用结尾不输出新行。这意味着如果希望任何文本从新的一行开始,那么需要明确写入print "\n"。 在主代码块中,创建了一个变量x来存储正在处理的当前字段的编号。起初,它被设置成1。然后,我们使用while循环(一种awk循环结构,等同于C语言中的while循环),对于所有记录(最后一个记录除外)重复打印记录和tab字符。最后,打印最后一个记录和换行;此外,由于将ORS设置成"",print将不输出换行。程序输出如下,这正是我们所期望的:
代码 1.10: 我们想要的输出。不算漂亮,但用tab定界,以便于导入电子表格 二、循环结构 awk的while循环结构,它等同于相应的C语言while循环。awk还有"do...while"循环,它在代码块结尾处对条件求值,而不象标准while循环那样在开始处求值。它类似于其它语言中的"repeat...until"循环。以下是一个示例:
代码 1.11: do...while示例
{
count=1 do { print "I get printed at least once no matter what" } while ( count != 1 ) } 与一般的while循环不同,由于在代码块之后对条件求值,"do...while"循环永远都至少执行一次。换句话说,当第一次遇到普通while循环时,如果条件为假,将永远不执行该循环。 for循环 awk允许创建for循环,它就象while循环,也等同于C语言的for循环:
代码 1.12: 循环示例
for ( initial assignment; comparison; increment ) {
code block } 以下是一个简短示例:
代码 1.13: 简短示例:
for ( x = 1; x <= 4; x++ ) {
print "iteration",x } 此段代码将打印:
代码 1.14: 上面代码的输出信息 此外,如同C语言一样,awk提供了break和continue语句。使用这些语句可以更好地控制awk的循环结构。以下是迫切需要break语句的代码片断:
代码 1.15: break语句所需的代码片断
while (1) {
print "forever and ever..." } while死循环1永远代表是真,这个while循环将永远运行下去。以下是一个只执行十次的循环:
代码 1.16: 只执行10次的循环
x=1
while(1) { print "iteration",x if ( x == 10 ) { break } x++ } 这里,break语句用于“逃出”最深层的循环。"break"使循环立即终止,并继续执行循环代码块后面的语句。 continue语句补充了break,其作用如下:
代码 1.17: 补充break的continue语句
x=1
while (1) { if ( x == 4 ) { x++ continue } print "iteration",x if ( x > 20 ) { break } x++ } 这段代码打印"iteration 1"到"iteration 21","iteration 4"除外。如果迭代等于4,则增加x并调用continue语句,该语句立即使awk开始执行下一个循环迭代,而不执行代码块的其余部分。如同break一样,continue语句适合各种awk迭代循环。在for循环主体中使用时,continue将使循环控制变量自动增加。以下是一个等价循环:
代码 1.18: 等价循环
for ( x=1; x<=21; x++ ) {
if ( x == 4 ) { continue } print "iteration",x } 在while循环中时,在调用continue之前没有必要增加x,因为for循环会自动增加x。 数组 如果您知道awk可以使用数组,您一定会感到高兴。然而,在awk中,数组下标通常从1开始,而不是0:
代码 1.19: awk数组示例 定义之后,awk有一个便利的机制来迭代数组元素,如下所示:
代码 1.20: 数组迭代
for ( x in myarray ) {
print myarray[x] } 这段代码将打印数组myarray中的每一个元素。当对于for使用这种特殊的"in"形式时,awk将myarray的每个现有下标依次赋值给x(循环控制变量),每次赋值以后都循环一次循环代码。虽然这是一个非常方便的awk功能,但它有一个缺点──当awk在数组下标之间轮转时,它不会依照任何特定的顺序。那就意味着我们不能知道以上代码的输出是:
代码 1.21: 以上代码的输出
代码 1.22: 上面代码的另一种输出 三,数组下标字符串化 在前一篇文章中,我演示了awk实际上以字符串格式来存储数字值。虽然awk要执行必要的转换来完成这项工作,但它却可以使用某些看起来很奇怪的代码:
代码 1.23: 奇怪的代码
代码 1.24: 示例代码
myarr["1"]="Mr. Whipple"
print myarr["1"] 可以预料,这段代码将打印"Mr. Whipple"。但如果去掉第二个"1"下标中的引号,情况又会怎样呢?
代码 1.25: 去掉引号的代码 了解了这个奇怪的真相之后,我们中的一些人可能想要执行类似于以下的古怪代码:
代码 1.26: 古怪的代码
myarr["name"]="Mr. Whipple"
print myarr["name"]
四、数组工具 谈到数组时,awk给予我们许多灵活性。可以使用字符串下标,而且不需要连续的数字序列下标(例如,可以定义myarr[1]和myarr[1000],但不定义其它所有元素)。虽然这些都很有用,但在某些情况下,会产生混淆。幸好,awk提供了一些实用功能有助于使数组变得更易于管理。 首先,可以删除数组元素。如果想要删除数组fooarray的元素1 ,输入:
代码 1.27: 删除数组元素
代码 1.28: 查看是否存在某个特定数组元素
if ( 1 in fooarray ) {
print "Ayep! It's there." } else { print "Nope! Can't find it." } 还是那句话,学习awk命令,建议多加练习,实践出真知,大家可以将上面的awk实例,都练习一遍。 (责任编辑:IT) |