在文本浏览和数据的熟练使用上性能优异。
可以说a w k是一种自解释的编程语言,之所以要在s h e l l中使用a w k
是因为a w k本身是学习的好例子,但结合a w k与其他工具诸如g r e p和s e d,将会使s h e l l编程更加
容易。本章仅注重于讲述使用a w k执行行操作及怎样从文本文件和字符串中抽取信息。
本书几乎所有包含a w k命令的脚本都结合了s e d和g r e p,以从文本文件和字符串中抽取信
息。为获得所需信息,文本必须格式化,意即用域分隔符划分抽取域,分隔符可能是任意字
符,在以后讲述a w k时再详细讨论。
a w k语言的最基本功能是在文件或字符串中基于指定规则浏览和抽取信息。a w k抽取信息
后,才能进行其他文本操作。完整的a w k脚本通常用来格式化文本文件中的信息。
awk脚本:
在命令中调用a w k时,a w k脚本由各种操作和模式组成。
如果设置了- F选项,则a w k每次读一条记录或一行,并使用指定的分隔符分隔指定域,但
如果未设置- F选项,a w k假定空格为域分隔符,并保持这个设置直到发现一新行。当新行出现
时,a w k命令获悉已读完整条记录,然后在下一个记录启动读命令,这个读进程将持续到文件
尾或文件不再存在。
模式和动作:
任何a w k语句都由模式和动作组成。在一个a w k脚本中可能有许多语句。模式部分决定动
作语句何时触发及触发事件。处理即对数据进行的操作。如果省略模式部分,动作将时刻保
持执行状态。
模式可以是任何条件语句或复合语句或正则表达式。模式包括两个特殊字段B E G I N和
E N D。使用B E G I N语句设置计数和打印头。B E G I N语句使用在任何文本浏览动作之前,之后
文本浏览动作依据输入文件开始执行。E N D语句用来在a w k完成文本浏览动作后打印输出文
本总数和结尾状态标志。如果不特别指明模式, a w k总是匹配或打印行数。
实际动作在大括号{ }内指明。动作大多数用来打印,但是还有些更长的代码诸如i f和循环
(l o o p i n g)语句及循环退出结构。如果不指明采取动作, a w k将打印出所有浏览出来的记录。
下面将深入讲解这些模式和动作。
域和记录:
a w k执行时,其浏览域标记为$ 1,$ 2 . . . $ n。这种方法称为域标识。使用这些域标识将更容
易对域进行进一步处理。
使用$ 1 , $ 3表示参照第1和第3域,注意这里用逗号做域分隔。如果希望打印一个有5个域
的记录的所有域,不必指明$ 1 , $ 2 , $ 3 , $ 4 , $ 5,可使用$ 0,意即所有域。Aw k浏览时,到达一新
行,即假定到达包含域的记录末尾,然后执行新记录下一行的读动作,并重新设置域分隔。
注意执行时不要混淆符号$和s h e l l提示符$,它们是不同的。
为打印一个域或所有域,使用p r i n t命令。这是一个a w k动作(动作语法用圆括号括起来)。
真正执行前看几个例子,现有一文本文件g r a d e . t x t,记录了一个称为柔道数据库的行信
息。
[root@localhost huangcd]# cat grade.txt
M.Tansley 05/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 26
P.Bunny 02/99 48 Yellow 12 35 28
J.Troll 07/99 4842 Brown-3 12 26 26
L.Tansley 05/99 4712 Brown-2 12 30 28
此文本文件有7个域,即(1)名字、(2)升段日期、(3)学生序号、(4)腰带级别、(5)
年龄、(6)目前比赛积分、(7)比赛最高分。
因为域间使用空格作为域分隔符,故不必用- F选项划分域,现浏览文件并导出一些数据。
在例子中为了利于显示,将空格加宽使各域看得更清晰。
2. 保存a w k输出
有两种方式保存s h e l l提示符下a w k脚本的输出。最简单的方式是使用输出重定向符号>文
件名,下面的例子重定向输出到文件w o w。
[root@localhost huangcd]# awk '{print $0}' grade.txt >wow
第二种方法是使用t e e命令,在输出到文件的同时输出到屏幕。在测试输出结果正确与否
时多使用这种方法。例如输出重定向到文件d e l e t e m e a n d d i e,同时输出到屏幕。使用这种
方法,在a w k命令结尾写入| tee delete_me_and_die。
[root@localhost huangcd]# awk '{print $0}' grade.txt |tee delete_me_and_die
M.Tansley 05/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 26
P.Bunny 02/99 48 Yellow 12 35 28
J.Troll 07/99 4842 Brown-3 12 26 26
L.Tansley 05/99 4712 Brown-2 12 30 28
3. 使用标准输入
在深入讲解这一章之前,先对a w k脚本的输入方法简要介绍一下。实际上任何脚本都是从
标准输入中接受输入的。为运行本章脚本,使用a w k脚本输入文件格式,例如:
a w k读每一条记录。因为没有模式部分,只有动作部分{print $0}(打印所有记录),这个动
作必须用花括号括起来。上述命令打印整个文件。
[root@localhost huangcd]# awk '{print $0}' grade.txt
M.Tansley 05/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 26
P.Bunny 02/99 48 Yellow 12 35 28
J.Troll 07/99 4842 Brown-3 12 26 26
L.Tansley 05/99 4712 Brown-2 12 30 28
假定只打印学生名字和腰带级别,通过查看域所在列,可知为f i e l d - 1和f i e l d - 4,因此可以
使用$ 1和$ 4,但不要忘了加逗号以分隔域。
[root@localhost huangcd]# awk '{print $1,$4}' grade.txt
M.Tansley Green
J.Lulu green
P.Bunny Yellow
J.Troll Brown-3
L.Tansley Brown-2
打印报告头:
上述命令输出在名字和腰带级别之间用一些空格使之更容易划分,也可以在域间使用t a b
键加以划分。为加入t a b键,使用t a b键速记引用符\ t,后面将对速记引用加以详细讨论。也可
以为输出文本加入信息头。本例中加入n a m e和b e l t及下划线。下划线使用\ n,强迫启动新行,
并在\ n下一行启动打印文本操作。打印信息头放置在B E G I N模式部分,因为打印信息头被界
定为一个动作,必须用大括号括起来。在a w k查看第一条记录前,信息头被打印。
[root@localhost huangcd]# awk 'BEGIN {print "Name Belt\n------------"}\
> {print $1"\t"$4}' grade.txt
Name Belt
------------
M.Tansley Green
J.Lulu green
P.Bunny Yellow
J.Troll Brown-3
L.Tansley Brown-2
如果在末行加入end of report信息,可使用E N D语句。E N D语句在所有文本处理动作执行
完之后才被执行。E N D语句在脚本中的位置放置在主要动作之后。下面简单打印头信息并告
之查询动作完成。
[root@localhost huangcd]# awk 'BEGIN {print "Name\n-------"} {print $1} END {"end-of-report"}' grade.txt
Name
-------
M.Tansley
J.Lulu
P.Bunny
J.Troll
L.Tansley
end-of-report
当第一次使用a w k时,可能被错误信息搅得不知所措,但通过长时间和不断的学习,可总
结出以下规则。在碰到a w k错误时,可相应查找:
• 确保整个a w k命令用单引号括起来。
• 确保命令内所有引号成对出现。
• 确保用花括号括起动作语句,用圆括号括起条件语句。
• 可能忘记使用花括号,也许你认为没有必要,但a w k不这样认为,将按之解释语法。
在g r e p一章中,有许多例子用到正则表达式,这里将不使用同样的例子,但可以使用条
件操作讲述a w k中正则表达式的用法。
这里正则表达式用斜线括起来。例如,在文本文件中查询字符串G r e e n,使用/ G r e e n /可以
查出单词G r e e n的出现情况。
这里是a w k中正则表达式匹配操作中经常用到的字符,详细情况请参阅本书第7章正则表
达式概述。
\ ^ $ . [] | () * + ?
这里有两个字符第7章没有讲到,因为它们只适用于a w k而不适用于g r e p或s e d。它们是:
+ 使用+匹配一个或多个字符。
? 匹配模式出现频率。例如使用/X Y?Z/匹配X Y Z或Y Z。
表9 - 2给出a w k条件操作符,后面将给出其用法。主要注意~(匹配正则表达式)和(!~)不匹配正则表达式。