前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >AWK中的字段,记录和变量【Programming】

AWK中的字段,记录和变量【Programming】

作者头像
Potato
修改2019-11-11 11:07:19
2K0
修改2019-11-11 11:07:19
举报

本文为awk入门系列的第二篇文章,在本篇文章中,你可以了解到有关字段,记录和一些功能强大的awk变量。

图片来源:  Pixabay, CC0
图片来源: Pixabay, CC0

Awk有很多变种:最初的awk于1977年在AT&T贝尔实验室诞生。在这之后有多种解释器,例如mawk ,nawk ,以及大多数Linux发行版,GNU awk或gawk附带的版本。在大多数Linux发行版中,awk和gawk是指代GNU awk的同义词,并且输入这其中任一命令都会调用相同的awk命令。如果想了解awk和gawk的历史版本和记录可以访问GNU awk用户指南

本系列的第一篇文章中展示了如何在命令行上调用awk,代码如下:

代码语言:txt
复制
$ awk [options] 'pattern {action}' inputfile

awk是可包含参数(例如-F来定义字段分隔符)的命令,至少在终端中使用该命令时您可以在单引号中声明自己想要进行的操作。如果想要进一步强调awk命令中的哪一部分是您要执行的操作,可以选择在程序前加上-e选项(非必须):

代码语言:javascript
复制
$ awk -F, -e '{print $2;}' colours.txt
yellow
blue
green
[...]

记录和字段

Awk通常将其输入数据视为以换行符分隔的一系列记录。也就是说,awk通常会将文本文件中的每一行视为新记录。每个记录包含一系列字段。而记录由字段分隔符分割后则组成了字段。

默认设置下,awk将空白(例如空格,制表符和换行符)视为新字段的指示符。总的来说,awk将多个空格分隔符视为一个,因此此行包含两个字段:

代码语言:javascript
复制
raspberry red

下面这个例子也包含了两个字段:

代码语言:javascript
复制
tuxedo                  black

其他分隔符并不能通过这​​种方式处理。假如设定字段分隔符是逗号,下面的例子中将包含三个字段,其中一个字段的长度可能为零个字符(不可打印字符未隐藏在该字段中的情况下):

代码语言:javascript
复制
a,,b

AWK程序

awk命令的程序部分由一系列规则组成。通常,每个规则都在程序中的新行开始(尽管这并不是强制性的)。 每个规则都包含一个模式和多种操作:

代码语言:javascript
复制
pattern { action }

在规则中,可以将模式定义为条件,以控制是否对记录进行操作。模式可以是简单的比较,正则表达式,两者的组合等等。

例如,仅当包含单词“ raspberry”时,才打印记录:

代码语言:javascript
复制
$ awk '/raspberry/ { print $0 }' colours.txt
raspberry red 99

如果没有限定模式,那么该操作将应用于每个记录。此外,规则只能包含一个模式,例如当操作是{print}时,整条记录都将被写入。正因为操作取决于数据,awk程序本质上是数据驱动的,这与许多其他编程语言程序有很大的不同。

NF变量

每个字段都有一个变量作为名称,但是字段和记录也有特殊的变量。变量NF存储awk在当前记录中找到的字段数。可以打印或在测试中使用。下面是使用上一篇文章中的文本文件的示例:

代码语言:javascript
复制
$ awk '{ print $0 " (" NF ")" }' colours.txt
name       color  amount (3)
apple      red    4 (3)
banana     yellow 6 (3)
[...]

Awk的print函数采用一系列参数(变量或字符串)并将它们连接在一起。这就是awk在每一行末尾将字段数打印为用括号括起来的整数的原因。

NR变量

除了对每个记录中的字段进行计数外,awk还对输入记录进行计数。记录号保存在变量NR中,并且可以与任何其他变量相同的方式使用。例如,要在每行之前打印记录号:

代码语言:javascript
复制
$ awk '{ print NR ": " $0 }' colours.txt
1: name       color  amount
2: apple      red    4
3: banana     yellow 6
4: raspberry  red    3
5: grape      purple 10
[...]

需要注意的是,使用以下命令时,除了打印后的空格以外不能有其它空格,尽管这样做会使内容更难去解析。

代码语言:javascript
复制
$ awk '{print NR": "$0}' colours.txt

printf()函数

使用awk printf()函数可以更灵活地格式化输出,这类似于使用C,Lua,Bash和其他语言的printf 函数——采用格式参数,后跟逗号分隔的数据列表,参数列表可以用括号括起来。

代码语言:javascript
复制
$ printf format, item1, item2, ...

format参数(或format string )定义了其他每个参数的输出方式。它使用格式说明符来执行此操作,其中包括%s(输出字符串)和%d(输出十进制数)。 下面的printf语句可以输出记录,后跟括号中的字段数:

代码语言:javascript
复制
$ awk 'printf "%s (%d)\n",$0,NF}' colours.txt
name       color  amount (3)
raspberry  red    4 (3)
banana     yellow 6 (3)
[...]

在此示例中,%s(%d)提供了每一行的结构,而$ 0,NF定义了要插入到%s和%d位置的数据。与打印功能不同的是,如果没有显式指令,那么就不会生成换行符进行换行。若要进行这个操作可以选择使用转义序列\ n。

AWK脚本

本文中的所有awk代码均已在交互式Bash提示符下编写并执行。 对于更复杂的程序,将命令放置到文件或脚本中通常会使它更容易。 选项-f FILE (不要与-F混淆,它表示字段分隔符)可用于调用包含程序的文件。

例如,这是一个简单的awk脚本。 请使用以下内容创建一个名为example1.awk的文件:

代码语言:javascript
复制
/^a/ {print "A: " $0}
/^b/ {print "B: " $0}

通常情况下,此类文件扩展名为.awk ,以明确表明它们包含awk程序。虽然这种命名并非强制要求,但它可以为文件管理器和编辑器(以及用户)提示文件内容和类型。

运行脚本:

代码语言:javascript
复制
$ awk -f example1.awk colours.txt
A: raspberry  red    4
B: banana     yellow 6
A: apple      green  8

可以通过在代码顶部添加一行#!来将包含awk指令的文件制作成脚本,并使其可执行。 使用以下内容创建一个名为example2.awk的文件:

代码语言:javascript
复制
#!/usr/bin/awk -f
#
# Print all but line 1 with the line number on the front
#

NR > 1 {
    printf "%d: %s\n",NR,$0
}

可以说,在脚本中只包含一行没有什么优势,但是有时执行脚本比记住并键入一行要容易得多。 脚本文件还提供了功能来记录命令做了些什么工作。 以#符号开头的行是注释,awk会忽略它们。

授予文件可执行权限:

代码语言:javascript
复制
$ chmod u+x example2.awk

运行脚本:

代码语言:javascript
复制
$ ./example2.awk colours.txt
2: apple      red    4
2: banana     yellow 6
4: raspberry red    3
5: grape      purple 10
[...]

将awk指令放在脚本文件中的一个好处是格式和编辑会变得更加容易。 虽然您可以在终端的一行中编写awk,但是当它跨越多行时,可读性和可维护性会变得很差。

尝试一下

现在您对awk如何处理指令以编写复杂的awk程序已经足够了解。可以尝试编写具有多个规则和至少一个条件模式的awk脚本。如果您想尝试除了print和printf以外的更多功能,请参考gawk手册

下面的例子希望能您能受到启发:

代码语言:javascript
复制
#!/usr/bin/awk -f
#
# Print each record EXCEPT
# IF the first record contains "raspberry",
# THEN replace "red" with "pi"

$1 == "raspberry" {
        gsub(/red/,"pi")
}

{ print }

使用此脚本来了解它的功能,然后尝试编写自己的脚本。

本系列的下一篇文章将介绍更多功能,用于更复杂也更有用的脚本。

本文改编自社区技术播客Hacker Public Radio

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 记录和字段
  • AWK程序
  • NF变量
  • NR变量
  • printf()函数
  • AWK脚本
  • 尝试一下
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档