AWK到底是什么?从字面上看,“AWK”这三个字母几乎不能给我们任何提示,他不象一些UNIX命令一样多多少少反映出了一些功能,如FIND和KILL一样,也不象另一些UNIX命令是功能的简写,如l是list(列表)的缩写,这些都能给我们多多少少一点提示,但awk不行. 事实上,AWK是三个程序大师首字符的缩写,这三个人分别是:Aho、(Peter)Weinberg和(Brain)Kernighan。正是这三个人创造了AWK。显然,这样的词汇组成形式不能给我们提供任何的帮助。
那么:AWK的功能到底是什么呢?实际上AWK是一种文本文件处理工具,这一点与sed和grep很相似,但awk所提供的功能却是sed和grep所无法望其项背的。awk提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上awk的确拥有自己的语言:awk程序设计语言,awk的三位创建者已将它正式定义为“样式扫描和处理语言”。
即使如此,你也许还要问:我为什么要用awk?的确,unix拥有很多优秀的工具,便如C语言就是一种功能强大的武器,我们又为什么要选择awk呢?这首先是因为awk是一个容易得到的工具:几乎每个UNIX系统都带有自己的awk,而C语言却是UNIX开发系统的一部分,如果你没有安装UNIX开发系统的话,你就不可能得到C语言。其次,awk是一个使用简单的工具,有些问题也许C语言可以解决,但你却不得不通过写源程序、调试、编译等等繁琐的步骤,而awk就根本不存在这个问题。最后,awk在实现某些功能方面,的确是比C语言更为便捷的工具,而这些却是更简单一些的工具例如shell和处理文件所无法实现的。例如我曾经试图用shell script写一个实现销售清单上销售金额的累加,然而shell只提供了整数型的数据变量,对于小数点后面的两位就无能为力了,而为了一个临时性的工作专门写一个C程序似乎又不值得,最后我想到了awk,结果非常轻松的实现了,也正是从那时起,我开始喜欢上awk了。在这里有一个可遵循的一般原则:如果你用普通的shell工具或shell script有困难的话,试试awk,如果awk仍不能解决问题,则便用C语言,如果C语言仍然失败,则移至C++。看了对awk的简要介绍,你也许对awk有学习和掌握的愿望了,既然如此,就让我们开始探索awk的新旅程吧!
一、awk的语法。
awk是以unix的一个命令的形式提供给用户的,你可以在/bin目录下找到awk这个文
件,如果缺少这个文件,你就不能运行awk。因此,awk拥有自己的调用语法:
awk [ -F re][parameter...]['prog'][-f progfile][in_file...]
参数说明:
re awk记录分隔符。
parameter 该参数帮助为不同的变量赋值。
'prog' awk的程序语句。(注意这里必须用单拓号:'和'括起,以防被shell
解释)
progfile awk程序文件。
in_file 输入文件,可以有多个。值得注意的是awk不修改输入文件。如果未
指定输入文件,awk将接受标准输入,并将结果显示在标准输出上。awk支持输入输出重
定向(<、>、>>、<<以及|)。
awk支持模式匹配,若没有给出模式,则对于输入文件中的所有行都有匹配的。
二、简单的应用:
例1:显示文件myfile中含有字符串"sun"的所有行:
awk '/sun/ {print}' myfile
在这里,模式/sun/匹配输入文件myfile中所有含有字符串'sun'的行并对其进行操作,
而程序语句print完成对该行的打印。
你也可以使用,号分开两模式以选定某个范围:
例2:显示文件myfile中第一个匹配Sun或sun的行与第一个匹配Moon或moon行之间
的行:
awk '/[Ss]un/,/[Mm]oon/ {print}' myfile
三、awk的字段:
awk的一个强大的功能是支持对字段的操作,这是grep和sed不能实现的。
所谓的字段,即是行中的一部分。在awk中,一般的情况下,将文本文件中的一行视
为一个记录,而将行中的不同部分称为“字段”。awk用$1,$2...的形式顺序的表示行中的
不同部分即不同字段。一般情况下awk将空白符视为字段间的分隔符,在awk中,用一个内
置的FS变量来确定所使用的字段分隔符。awk允许用-F先项改变默认的字段分隔符。同样,
在awk中你也可以通过修改记录分隔符变量RS来改变默认的记录分隔符。
在awk中用内置变量NR来表示当前工作的记录数。我们可以将其应用于模式匹配中用
来指定工作范围:
例3:显示文本文件myfile中第七行到第十五行中以字符%分隔的第一字段,第三字段和
第七字段:
awk -F % 'NR==7,NR==15 {printf $1 $3 $7}' myfile
四、printf语句
awk可以通过调用用一对单引号括起来的一系列语句来完成一些较为复杂的功能。前面
我们已经遇到过的print就是awk的语句之一。awk也支持独立的awk程序的调用,其方法是在
命令行中加上-f <程序文件名>参数。
awk融合了许多C语言的待点,因此,如果你熟悉C语言的话对使用awk将有极大的帮助,
实际上,awk中有许多引用形式都是从C语言借用过来的,如我们下面要看到的printf函数就
是一个例子。
如果你熟悉C语言,你也许会怀念其中的printf函数,它提供的强大格式输出功能曾经
带我们许多的方便。幸运的是,我们在awk中又和它重逢了。awk中printf几乎与C语言中一模
一样,如果你熟悉C语言的话,你完全可以照C语言的模式使用awk中的printf。因此在这里,
我们只给出一个例子,如果你不熟悉的话,请随便找一本C语言的入门书翻翻。
例4:显示文件myfile中的行号和第3字段:
$awk '{printf"%03d%s\n",NR,$1}' myfile
值得注意的一点是awk中的内置变量(如这里的NR)不须要以$开头。
对于awk中的其它语句,我们将在后面继续讨论。
五、awk程序设计
前面曾经说过awk提供了整套程序设计语言,包括变量、关系判断、流程控制等等,下面
我们分别说说其中的用法:
(一)、变量:
awk允许在程序语言中设置变量,事实上,提供变量的功能是程序设计语言的其本要求,
不提供变量的程序设计语言本人还从未见过。awk提供两种变量,一种是awk内置的变量,如前面
提到的NR、RS都属于此种范畴,如果你还知道awk提供了哪些其它的内置变量,请参考本文后面
的附录。awk也允许用户在awk程序语句中定义并调用自已的变量。与C语言不同的是,awk中不需
要对变量进行初始化,awk根据其在awk中第一次出现的形式和上下文确定其具体的数据类型。
当变量类型不确定时,awk设定其为字符串类型。
(二)、运算与判断:
awk支持C语言提供的大多数运算:如+、-、*、/、%等等,也支持关系判断,如<、>、>=
等等,也支持用逻辑运算符:!(非)、&&(与)、||(或)和()进行多重判断,这大大增强了awk
的功能。
awk也支持C语言中类似++、--、+=、-=、=+、=-之类的功能,这给熟悉C语言的使用者编写
awk程序带来了极大的方便。
在awk中为了实现某些运算功能,提供了一些内置的函数,如log、sqr、cos、sin等等,同
时,awk也提供了用于对字符串进行操作(运算)的函数如length、substr等等。
awk提供的具体的运算与判断功能请参考文后的附录。
(三)、流程控制
awk提供了完备的类似C语言的流程控制语句,这给我们编程带来了极大的方便。
1、BEGIN和END
在awk中两个特别的表达式,BEGIN和END可用于pattern中,任何在BEGIN之后列出的操作(
在{}内)将在awk开始扫描输入之前执行,而END之后列出的操作将在扫描完全部的输入之后报废行。
因此,通常使用BEGIN来显示变量和预置(初始化)变量,使用END来输出最终结果。
例5:累计销售文件xs中的销售金额(假设销售金额在记录的第三字段):
$awk
>'BEGIN { FS=":";print "统计销售金额";total=0}
>{print $3;total=total+$3;}
>END {printf "销售金额总计:%.2f",total}' sx
(注:>是shell提供的第二提示符,如要在shell程序awk语句和awk语言中换行,则需在行尾加
反斜杠\)
在这里BEGIN预置了内部变量FS(字段分隔符)和自定义变量total,同时在扫描之前显示出输出
行头。而END则在扫描完成后打印出总合计。
2、流程控制语句
awk提供了完备的流程控制语句,其用法与C语言类似。下面我们一一加以说明:
if...else语句:
格式:
if(表达式)
语句1
else
语句2
格式中"语句1"可以是多个语句,如果你为了方便awk判断也方便你自已阅读,你最好将多个语句
用{}括起来。
awk分枝结构允许嵌套,其格式为
if(表达式1)
{if(表达式2)
语句1
else
语句2
}
语句3
else {if(表达式3)
语句4
else
语句5
}
语句6
当然实际操作过程中你可能不会用到如此复杂的分枝结构,这里只是为了给出其样式罢了。
while语句
格式为
while(表达式)
语句
for语句
格式为:
for(初始表达式;终止条件;步长表达式)
语句
在awk while和for语句中允许使用break,continue语句来控制流程走向,也允许使用exit这样的
语句来退出。
好了,awk就介绍到这里,说实在话,就这些内容都是awk的初步知识,电脑永远是前进的科学,
要想跟上它的步伐就得不断前行,但愿本篇能在你前行的漫漫长途中铺平一段小小的路程,能如此,则
愿已偿。
附录:
awk内置变量
变量名 含义
ARGC 命令行参数个数
ARGV 命令行参数数组
FILENAME string=当前输入的文件名
FNR 在当前文件中当前记录数(对输入文件起始为1)
FS 输入字段分隔符
NF 当前记录的字段数
NR 当前记录数(为全部输入文件)
OFMT 数值的输出格式(默认为%.6g)
OFS 输出字段的分隔符(默认为空格)
ORS 输出记录分隔符(默认为换行符)
RS 输入记录分隔符(默认为换行符)
awk允许的测试:
操作符 含义
x==y x等于y?
x!=y x不等于y?
x>y x大于y?
x>=y x大于或等于y?
x
x~re x匹配正则表达式re?
x!~re x不匹配正则表达式re?
awk的操作符(按优先级升序排列)
= 、+=、 -=、 *= 、/= 、 %=
||
&&
> >= < <= == != ~ !~
xy (字符串连结,'x''y'变成"xy")
+ -
* / %
++ --
awk的函数
int(x) 对x取整
rand 取 0到1之间的随机数
srand(x) 设置x为rand的新输入值
cos(x) 给出x的余弦值
sin(x) 给出x的正弦值
atan2(x,y) 给出y/x的正切值
exp(x) 给出e的x次幂
log(x) 给出x的常用对数值(基为e)
sqrt(x) 给出x的正平方根值
exit(x) 结束awk程序,若有x值,则返回x,否则返回0.
index(s,t) 返回t在s中的第一个开始位置,如t不是s的子串,则返回0]
length(x) 求x的长度(字符个数)
substr(s,x,y) 在字符串s中取得从x个字符开始的长度为y的子字符串.