6.2. print 程序

6.2.1. 打印选定的字段

print 命令在 awk 中输出来自输入文件的选定数据。

awk 读取文件的一行时,它会根据指定的输入字段分隔符将该行划分为字段,FS,这是一个 awk 变量(参见 第 6.3.2 节)。此变量预定义为一个或多个空格或制表符。

变量$1, $2, $3, ..., $N保存输入行中第一个、第二个、第三个直到最后一个字段的值。变量$0(零) 保存整行的值。下图对此进行了描述,我们在 df 命令的输出中看到了六列

图 6-1. awk 中的字段

ls -l 的输出中,有 9 列。print 语句按如下方式使用这些字段

kelly@octarine ~/test> ls -l | awk '{ print $5 $9 }'
160orig
121script.sed
120temp_file
126test
120twolines
441txt2html.sh

kelly@octarine ~/test>

此命令打印了长文件列表的第五列(其中包含文件大小)和最后一列(文件名)。除非您使用引用列的官方方式(即用逗号分隔您要打印的列),否则此输出的可读性不高。在这种情况下,默认输出分隔符(通常是空格)将放在每个输出字段之间。

Note本地配置
 

请注意,您的系统上 ls -l 命令的输出配置可能有所不同。时间和日期的显示取决于您的区域设置。

6.2.2. 格式化字段

如果不进行格式化,仅使用输出分隔符,则输出看起来相当糟糕。插入几个制表符和一个字符串来指示这是什么输出,将使其看起来好得多

kelly@octarine ~/test> ls -ldh * | grep -v total | \ 
awk '{ print "Size is " $5 " bytes for " $9 }'
Size is 160 bytes for orig
Size is 121 bytes for script.sed
Size is 120 bytes for temp_file
Size is 126 bytes for test
Size is 120 bytes for twolines
Size is 441 bytes for txt2html.sh

kelly@octarine ~/test>

请注意反斜杠的使用,它使长输入可以在下一行继续,而不会被 shell 解释为单独的命令。虽然您的命令行输入可以具有几乎无限的长度,但您的显示器不是,印刷的纸张肯定也不是。使用反斜杠还允许将上述行复制并粘贴到终端窗口中。

The-h选项用于 ls,为较大的文件提供人类可读的大小格式。当目录作为参数时,会给出显示目录中块总数的长列表输出。此行对我们无用,因此我们添加一个星号。我们还添加了-d选项,原因相同,以防星号扩展为目录。

此示例中的反斜杠标记行的延续。请参阅 第 3.3.2 节

您可以取出任意数量的列,甚至可以颠倒顺序。在下面的示例中,演示了如何显示最关键的分区

kelly@octarine ~> df -h | sort -rnk 5 | head -3 | \ 
awk '{ print "Partition " $6 "\t: " $5 " full!" }'
Partition /var  : 86% full!
Partition /usr  : 85% full!
Partition /home : 70% full!

kelly@octarine ~>

下表概述了特殊的格式化字符

表 6-1. gawk 的格式化字符

序列含义
\a响铃字符
\n换行符
\t制表符

引号、美元符号和其他元字符应使用反斜杠进行转义。

6.2.3. print 命令和正则表达式

正则表达式可以用作模式,方法是用斜杠将其括起来。然后针对每个记录的整个文本测试正则表达式。语法如下

awk '表达式 { 程序 }'文件

以下示例仅显示本地磁盘设备信息,不显示网络文件系统

kelly is in ~> df -h | awk '/dev\/hd/ { print $6 "\t: " $5 }'
/       : 46%
/boot   : 10%
/opt    : 84%
/usr    : 97%
/var    : 73%
/.vol1  : 8%

kelly is in ~>

斜杠需要转义,因为它们对 awk 程序具有特殊含义。

下面是另一个示例,我们在/etc目录中搜索以 ".conf" 结尾并以 "a" "x" 开头的文件,使用扩展正则表达式

kelly is in /etc> ls -l | awk '/\<(a|x).*\.conf$/ { print $9 }'
amd.conf
antivir.conf
xcdroast.conf
xinetd.conf

kelly is in /etc>

此示例说明了点号在正则表达式中的特殊含义:第一个点号表示我们要搜索第一个搜索字符串之后的任何字符,第二个点号被转义,因为它是一个要查找的字符串的一部分(文件名的结尾)。

6.2.4. 特殊模式

为了在输出前添加注释,请使用 BEGIN 语句

kelly is in /etc> ls -l | \
awk 'BEGIN { print "Files found:\n" } /\<[a|x].*\.conf$/ { print $9 }'
Files found:
amd.conf
antivir.conf
xcdroast.conf
xinetd.conf

kelly is in /etc>

可以添加 END 语句,以便在处理完整个输入后插入文本

kelly is in /etc> ls -l | \
awk '/\<[a|x].*\.conf$/ { print $9 } END { print \
"Can I do anything else for you, mistress?" }'
amd.conf
antivir.conf
xcdroast.conf
xinetd.conf
Can I do anything else for you, mistress?

kelly is in /etc>

6.2.5. Gawk 脚本

随着命令变得越来越长,您可能希望将它们放在脚本中,以便它们可以重用。awk 脚本包含定义模式和操作的 awk 语句。

作为说明,我们将构建一个报告,显示我们负载最重的分区。请参阅 第 6.2.2 节

kelly is in ~> cat diskrep.awk
BEGIN { print "*** WARNING WARNING WARNING ***" }
/\<[8|9][0-9]%/ { print "Partition " $6 "\t: " $5 " full!" }
END { print "*** Give money for new disks URGENTLY! ***" }

kelly is in ~> df -h | awk -f diskrep.awk
*** WARNING WARNING WARNING ***
Partition /usr  : 97% full!
*** Give money for new disks URGENTLY! ***

kelly is in ~>

awk 首先打印开始消息,然后格式化所有在单词开头包含八或九,后跟另一个数字和百分号的行。添加了结束消息。

Note语法高亮
 

Awk 是一种编程语言。它的语法被大多数可以为其他语言(例如 C、Bash、HTML 等)进行语法高亮的编辑器所识别。