6.3. Gawk 变量

awk 处理输入文件时,它会使用多个变量。有些变量是可编辑的,有些是只读的。

6.3.1. 输入字段分隔符

字段分隔符,可以是单个字符或正则表达式,控制着 awk 将输入记录拆分为字段的方式。输入记录会被扫描以查找与分隔符定义匹配的字符序列;字段本身是匹配项之间的文本。

字段分隔符由内置变量表示FS。请注意,这与IFSPOSIX 兼容的 shell 使用的变量不同。

字段分隔符变量的值可以在 awk 程序中使用赋值运算符 = 来更改。通常,执行此操作的合适时机是在执行开始之前,在任何输入被处理之前,以便使用正确的分隔符读取第一个记录。为此,请使用特殊的 BEGIN 模式。

在下面的示例中,我们构建一个命令,该命令显示系统上所有用户及其描述

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

但是一个人可能拥有博士学位,并且可能像这样书写

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

您的 awk 将为此行提供错误的输出。如果需要,请使用额外的 awksed 来统一数据输入格式。

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

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. 更多示例

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 脚本时,来自 第 5.3.2 节 的示例变得更加容易

kelly@octarine ~/html> awk -f make-html-from-text.awk testfile > file.html

Tip当使用 awk 而不是 sed 时,要执行的命令也更加直接
 

您系统上的 Awk 示例

我们再次参考包含您系统上 initscripts 的目录。输入类似于以下内容的命令,以查看 awk 命令广泛使用的更多实际示例grep awk

/etc/init.d/*

6.3.6. printf 程序

为了比 print 通常提供的输出格式更精确的控制,请使用 printfprintf 命令可用于指定每个项目的字段宽度,以及数字的各种格式化选项(例如使用哪个输出基数,是否打印指数,是否打印符号以及小数点后打印多少位数字)。这是通过提供一个称为格式字符串的字符串来完成的,该字符串控制如何以及在何处打印其他参数。