ITEEDU

6.3. Gawk变量

既然 awk 处理输入文件,他使用几个变量。一些是可以编辑的,一些是只读的。

6.3.1. 输入域的分隔符

域分隔符,既不是一个单独的字符也不是一个普通的表达式,是控制 awk 把一个输入分割成几个域。输入记录按分割定义进行字符顺序扫描;域就是在相符的那些文字中间的那部分。

域分隔符代表内建的变量 FS,注意POSIX标准的shell使用的变量 IFS 和他是有一些区别的。

域分隔符变量的值可以在 awk 程序中用赋值操作符 = 来改变。通常最好的执行时间是一开始也就是还没有处理任何输入的时候,因此第一个记录就被随合适的分隔符一起读取。要这么做,清使用特殊的 BEGIN pattern。

以下的例子,我们编制了一条命令来显示系统里的所有用户及其描述:

kelly is in ~> awk 'BEGIN { FS=":" } { print $1 "\t" $5 }' /etc/passwd
--output omitted--
kelly	Kelly Smith
franky	Franky B.
eddy	Eddy White
willy	William Black
cathy	Catherine the Great
sandy	Sandy Li Wong

kelly is in ~>

在一个 awk 脚本中,它看起来像这样:

kelly is in ~> cat printnames.awk
BEGIN { FS=":" }
{ print $1 "\t" $5 }

kelly is in ~> awk -f printnames.awk /etc/passwd
--output omitted--

小心地选择输入分隔域来防止出现问题。一个例子来说明这个:说你需要输入想这样的行的形式:

Sandy L. Wong, 64 Zoo St., Antwerp, 2000X

你这样写了一个打印出记录中人的名字的命令行或者是脚本:

awk 'BEGIN { FS="," } { print $1, $2, $3 }' inputfile

但是可能一个人有PhD,而且可能写成这样:

Sandy L. Wong, PhD, 64 Zoo St., Antwerp, 2000X

你的 awk 会给出错误的输出。需要的话,使用额外的一个 awk 或者 sed 来统一数据输出的格式。

默认的输入分隔符是一个或多个空格和制表符。

6.3.2. 输出分隔符

6.3.2.1. 输出域分隔符

在输出中域通常被空格分隔。当你对 print 命令使用正确的语法且字段用逗号分隔时,这将很明显的:

kelly@octarine ~/test> cat test
record1         data1
record2         data2

kelly@octarine ~/test> awk '{ print $1 $2}' test
record1data1
record2data2

kelly@octarine ~/test> awk '{ print $1, $2}' test
record1 data1
record2 data2

kelly@octarine ~/test>

如果你不输入逗号, print 将把输出的项目全部当成一个字段,因此省略默认输出 分隔符, OFS的使用。

在摄制了这个内建变量的值之后任何字符串可以被用作一个输出域。

6.3.2.2. 输出记录分隔符

整个 print 语句的输出叫做输出记录。每个在输出记录里的print命令的结果,输出一个叫做 输出记录分隔符 ORS的字符串。这个变量的默认值是 “\n”,一个换行符。因此,每个 print 语句生成一个单独的行。

要改变输出域和记录的,只要给 OFSORS 赋新的值:

kelly@octarine ~/test> awk 'BEGIN { OFS=";" ; ORS="\n-->\n" } \
{ print $1,$2}' test
record1;data1
-->
record2;data2
-->

kelly@octarine ~/test>

如果 ORS 的值不包含换行,那么程序中的输出就会输出成一个单独行。

6.3.3. 记录的数量

内建的 NR 包含了处理过的记录的数量。在读入一个新的输入行之后他会自行增加一次。你可以用它来计算记录的总数,或者在每个输出记录中:

kelly@octarine ~/test> cat processed.awk
BEGIN { OFS="-" ; ORS="\n--> done\n" }
{ print "Record number " NR ":\t" $1,$2 }
END { print "Number of records processed: " NR }

kelly@octarine ~/test> awk -f processed.awk test
Record number 1:        record1-data1
--> done
Record number 2:        record2-data2
--> done
Number of records processed: 2
--> done

kelly@octarine ~/test>

6.3.4. 用户定义的变量

除了内建的变量之外,你也可以定义自己的变量。当 awk 碰到一个不存在的变量(没有事先定义的)的引用时,这个变量就被创建并且使用一个空字符串进行赋值。对于后来所有的引用,就是该变量最后被赋予的那个值。变量可以是一个字符串或者一个数字。输入域的内容也可以被赋予变量。

值可以直接用 = 来赋值,或者你可以使用现有变量的值和其他操作符组合:

kelly@octarine ~> cat revenues
20021009        20021013        consultancy     BigComp         2500
20021015        20021020        training        EduComp         2000
20021112        20021123        appdev          SmartComp       10000
20021204        20021215        training        EduComp         5000

kelly@octarine ~> cat total.awk
{ total=total + $5 }
{ print "Send bill for " $5 " dollar to " $4 }
END { print "---------------------------------\nTotal revenue: " total }

kelly@octarine ~> awk -f total.awk test
Send bill for 2500 dollar to BigComp
Send bill for 2000 dollar to EduComp
Send bill for 10000 dollar to SmartComp
Send bill for 5000 dollar to EduComp
---------------------------------
Total revenue: 19500

kelly@octarine ~>

类似于C的简写 VAR+= value 也是可以接受的。

6.3.5. 更多例子

当我们使用 awk 脚本时, 第 5.3.2 节 “写输出文件” 的例子会变得更加容易:

kelly@octarine ~/html> cat make-html-from-text.awk
BEGIN { print "<html>\n<head><title>Awk-generated HTML</title></head>\n<body bgcolor=\"#ffffff\">\n<pre>" }
{ print $0 }
END { print "</pre>\n</body>\n</html>" }

而且当用 awk 来替代 sed 后,命令也变得更加直截了当:

kelly@octarine ~/html> awk -f make-html-from-text.awk testfile > file.html
[提示] 在你系统上的awk例子。

我们再次回到包含你系统启动脚本的目录。输入一个和以下相似的命令来查看更多 awk 命令的使用方法:

grep awk /etc/init.d/*

6.3.6. printf程序

为了更精确的控制 print 提供的正常输出格式,可以使用 printfprintf命令可以用来指明每个项目使用的域的宽度,同时也有用于数字的多种格式选择。这一切只要增加一个字符串,叫做格式字符串,控制怎样和那里来打印那些项目。

语法也和C语言的 printf 语句相似;请察看你的C介绍手册。 gawk 信息页面包含完整的解释。