1、前言

awkUnix环境下一种非常好的语言,适合于文本处理和报表生成,它还有许多精心设计的特性,允许进行特殊技巧程序设计。对于短消息来说,比如处理话单文件,使用awk就非常方便,鉴于测试组大部分人对awk并不熟悉,因此仅以本文作一个提纲挈领的介绍,希望对初学者迅速掌握awk有所帮助。

2、第一部分:入门

2.1 第一个awk程序

所有的编程书籍都是通过一个“Hello world!”简单程序入门,作为借鉴,本文也采用此方法带大家入门。现在,在当前目录下建立一个文本文件hello.txt,内容如下:

Hello world!

在命令行中输入以下命令

  1. awk '{print}' hello.txt 

执行后hello.txt文件的内容显示在屏幕上。编写并且执行awk程序的方法很简单,如上所示,花括号内的是程序代码,后面的hello.txt为指定的输入文件。awk是一种行处理程序,执行awk时,它依次对输入文件中的每一行执行花括号中的代码,如上面的例子,就是对hello.txt中的每一行执行print命令。所有输出都发送到stdout,最后在屏幕上显示的结果为“Hello world!”。

上面的例子是将脚本作为命令行自变量传递给awk,我们也可以把脚本写入一个外部文件,然后通过-f选项向awk传递这个脚本文件。例如编写脚本文件hello.awk如下:

  1. {print} 

然后通过如下方式执行:

  1. awk -f hello.awk hello.txt 

这种编写独立脚本文件的方式应用在多行、比较复杂的程序上,非常合适,而且,在后面你还将看到,这种方式还可以让你非常方便地使用附加awk功能。

2.2 常用变量 

awk有自己的特殊变量集合。其中一些允许调整awk的运行方式,而其它变量可以被读取以收集关于输入的有用信息。下面列举出最基本的几个常用变量,并用例子一一说明用法.

Awk特殊变量

描述

$number

表示记录的字段。比如,$1表示第1个字段,$2表示第2个字段,如此类推。而$0比较特殊,表示整个当前行

FS

表示字段分隔符

NF

表示当前记录中的字段数量

NR

表示当前记录的编号(awk将第一个记录算作记录号1

 为了便于举例说明,在当前目录下生成一个历史话单文件bill(注意,是一行内容,中间没有换行符),其内容如下:

4429300,0,8613902700001,8613902700002,8613800288500,2004/06/26 10:31:33,2004/06/26 10:31:33,0,0,0,4,6,1,0,0,0,,0,2004/06/26 10:31:32,NULL,1,0,0,nihao@,
4429300,0,8613902700001,8613902700003,8613800288500,2004/06/26 10:31:33,2004/06/26 10:31:33,0,0,0,4,6,1,0,0,0,,0,2004/06/26 10:31:32,NULL,1,0,0,nihao@,

 我们可以使用$0变量将整个bill文件内容读出:

  1. awk '{ print $0 }' bill 

 可以看出,在awk中,printprint $0的作用完全一样。

使用$number变量,对多个字段的文本进行处理,将变得非常容易,它可以让你毫不费力地引用每个独立的字段。例如,我们可以列出主叫号码和被叫号码:

  1. awk -F"," '{ print $3,$4 }' bill 

上例中,在调用awk时,使用-F选项来指定","作为字段分隔符。awk处理后打印出主叫号码字段和被叫号码字段。而且,你还可以在字段中插入字符,比如:

  1. awk -F"," '{ print "OrgAddr: "$3, "\tDestAddr: "$4 }' bill 

以下是该脚本输出:

OrgAddr: 8613902700001 DestAddr: 8613902700002
OrgAddr: 8613902700001 DestAddr: 8613902700003

以上命令中,我们是通过-F选项来指定字段分隔符的。如果我们使用的是脚本文件,则就要用到FS变量来设置字段分隔符。编写脚本文件bill.awk如下:

  1. BEGIN { 
  2.     FS="," 
  3.   
  4. print "OrgAddr: "$3"\tDestAddr: "$4 } 

 

建议最好用脚本文件,这样方便日后重复利用,也方便修改。

FS值并没有被限制为单一字符,可以通过指定任意长度的字符模式,将它设置成正则表达式。如果正在处理由一个或多个tab分隔的字段,可以按以下方式设置FS

  1. FS="\t+" 

 另外,这个脚本里出现了陌生的BEGIN,有必要解释一下。通常,对于每个输入行,awk都会执行每个脚本代码块一次。然而,在许多编程情况中,可能需要在awk开始处理输入文件中的文本之前执行初始化代码。对于这种情况,awk允许你定义一个BEGIN块。我们在上面的例子中使用了BEGIN块。因为awk在开始处理输入文件之前会执行BEGIN块,因此它是初始化FS(字段分隔符)变量、打印页眉或初始化其它在程序中以后会引用的全局变量的极佳位置。

awk还提供了另一个特殊块,叫作END块。awk在处理了输入文件中的所有行之后执行这个块。通常,END块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。

NF变量,也叫做“字段数量”变量。awk会自动将该变量设置成当前记录中的字段数量。可以使用NF变量来只显示某些输入行:

  1. NF == 3 { print $1,$2,$3 } 

NR变量始终包含当前记录的编号(awk将第一个记录算作记录号1)。迄今为止,我们处理的输入文件每一行包含一个记录,对于这些情况,NR就是当前行号。可以象使用NF变量一样使用NR来只打印某些输入行:

  1. (NR < 10 ) || (NR > 100) { print "We are on record number 1-9 or 101+" } 

在本文的第二部分我们还会讨论两个特别有用的特殊变量。