在本系列的第二部分中,我们将学习字段、记录和一些非常有用的Awk变量。awk有几个变种:??最早的awk是1977年由AT&T贝尔实验室创建的。它还有一些重构版本,比如mawk、nawk。在大多数Linux发行版中找到的是GNUawk,也称为gawk。在大多数Linux发行版中,awk和gawk是GNUawk的软链接。输入awk调用相同的命令。awk和gawk的完整历史可以在GNUawk用户手册中找到。本系列的第一篇文章介绍了awk命令的基本格式:$awk[options]'pattern{action}'inputfileawk是一个命令后面跟着选项(比如-F来定义字段分隔符)。您希望awk执行的部分需要写在两个单引号之间,至少在终端中是这样。在awk命令中,为了进一步强调你要执行的部分,可以使用-e选项来高亮显示(但不是必须的):$awk-F,-e'{print$2;}'colours。txtyellowbluegreen[...]记录和字段awk将输入数据视为一系列记录,通常按行拆分。换句话说,awk将每一行文本视为一条记录。每条记录包含多个字段。字段由字段定界符分隔,字段是记录的一部分。默认情况下,awk将各种空白字符(如空格、制表符、换行符等)视为分隔符。值得注意的是,在awk中,多个空格被视为一个分隔符。所以下面这行文字有两个字段:raspberryred这一行也是:tuxedoblack其他分隔符在程序中没有这样处理。假设字段分隔符是逗号,下面显示的记录有三个字段。其中一个字段可能为0字节(假设该字段中不包含隐藏字符)a,,bawk程序awk命令的程序部分由一系列规则组成。通常,程序中的每条规则占一行(尽管这不是必需的)。每条规则由一个模式或一个或多个动作组成:pattern{action}在规则中,您可以定义模式以确定该动作是否将在记录中执行。模式可以是简单的比较条件、正则表达式,甚至是两者的组合。在这个例子中,程序将只显示包含单词“raspberry”的记录:$awk'/raspberry/{print$0}'colours.txtraspberryred99如果没有文本与模式匹配,该操作将应用于所有记录。另外,当规则只包含模式时,相当于对整条记录执行{print}并将其全部打印出来。awk程序本质上是数据驱动的,命令执行的结果依赖于数据。因此,与其他编程语言的程序相比,它仍然有些不同。NF变量每个字段都有指定的变量,但也有一些字段和记录的特殊变量。NF变量,它存储awk在当前记录中找到的字段数。其内容可以显示在屏幕上,也可以用于测试。下面例子中的数据来自上一篇文章的文本:$awk'{print$0"("NF")"}'colours.txtnamecoloramount(3)applered4(3)bananayellow6(3)[...]awk的print函数接受一系列参数(可以是变量或字符串)并将它们连接起来。这就是为什么在此示例中,awk在每一行的末尾将字段数作为括在括号中的整数给出。NR变量除了统计每条记录的字段数,awk还统计输入记录的数量。记录数存储在变量NR中,它的使用方式与任何其他变量一样。例如,在每行的开头显示行号:$awk'{printNR":"$0}'colours.txt1:namecoloramount2:applered43:bananayellow64:raspberryred35:grapepurple10[...]请注意,您可以在打印后不在多个参数之间添加空格的情况下编写此命令,尽管这会降低可读性:$awk'{printNR":"$0}'colours.txtprintf()functioninordertomake输出结果对于更灵活的格式,可以使用awk的printf()函数。它类似于C、Lua、Bash和其他语言中的printf。它还接受以逗号分隔的格式参数。参数列表需要写在括号中。$printfformat,item1,item2,...format这个参数(也叫格式说明符)定义了其他参数如何显示。此功能是使用格式修饰符实现的。%s打印字符,%d打印十进制数。以下printf语句将在括号中显示字段数:$awk'printf"%s(%d)\n",$0,NF}'colours.txtnamecoloramount(3)raspberryred4(3)bananayellow6(3)[...]在本例中,%s(%d)定义了每一行的输出格式,$0,NF定义了要插入到%s和%d位置的数据。请注意,与打印功能不同,如果没有明确的指示,输出不会转到下一行。只有在出现转义字符\n时才会出现换行符。本篇Awk脚本中出现的所有awk代码均已在Bash终端中执行。对于更复杂的程序,将命令放在文件(脚本)中会更容易。-fFILE选项(不要与用于字段分隔符的-F混淆)可用于指定包含可执行程序的文件。例如,以下是一个简单的awk脚本。创建一个名为example1.awk的文件,内容如下:/^a/{print"A:"$0}/^b/{print"B:"$0}如果文件包含awk程序,则将文件命名为,它最好写.awk的扩展名。这样的命名不是强制性的,但这样做会给文件管理员、编辑者(和你)一个关于文件内容的有用提示。执行这个脚本:$awk-fexample1.awkcolours.txtA:树莓红4B:香蕉黄6A:苹果绿8包含awk命令的文件,添加#!执行脚本。创建一个名为example2.awk的文件,内容如下:#!/usr/bin/awk-f##在除第一行之外的所有行之前显示行号#NR>1{printf"%d:%s\n",NR,$0}可以说,脚本中只有一行,大多数时候是无用的。但在某些情况下,执行脚本比记住并键入命令要容易得多。脚本文件还提供了一个很好的机会来准确记录命令的作用。以#符号开头的行是注释,awk会忽略它们。赋予文件可执行权限:$chmodu+xexample2.awk执行脚本:$./example2.awkcolours.txt2:applered42:bananayellow64:raspberryred35:grapepurple10[...]willawkcommand放在脚本文件中的好处是更容易修改和格式化输出。在终端中,如果一行可以执行多个awk命令,输入多行达到同样的效果是多余的。试一试您现在已经足够了解awk如何执行命令了。现在您应该能够编写复杂的awk程序了。尝试编写一个awk脚本:至少包括一个条件模式和多个规则。如果想使用print和printf以外的函数,可以参考gawk在线手册。这个例子是一个很好的起点:#!/usr/bin/awk-f##Showallrecordsexcept#ifthefirstrecordcontains"raspberry"#replace"red"with"pi"$1=="raspberry"{gsub(/red/,"pi")}{print}尝试执行此脚本并查看输出结果。然后就看你了。本系列的下一篇文章将介绍更多可用于更复杂(也更有用!)脚本的函数。
