学习 awk 的实用指南

下载我们的免费电子书,更好地掌握 awk 命令。
129 位读者喜欢这个。
Why and how to handle exceptions in Python Flask

图片来自 Unsplash.com,知识共享 Zero 

在所有 Linux 命令中(有很多),最典型的三个似乎是 sedawkgrep。 也许是它们名字的神秘感,或者是它们潜在用途的广泛性,或者仅仅是它们的年代久远,但当有人举例说明“Linux 式”命令时,通常是这三个命令之一。 虽然 sedgrep 有几个简单的一行标准,但不太知名的 awk 仍然因其特别令人费解而一直突出。

您很可能每天使用 sed 进行快速字符串替换,或使用 grep 过滤模式。 您不太可能编写 awk 命令。 我经常想知道这是为什么,我将其归因于以下几点。 首先,我们中的许多人很少使用 sedgrep,除了这两个命令的一些变体之外

$ sed -e 's/foo/bar/g' file.txt
$ grep foo file.txt

因此,即使您可能对 sedgrep 感到更舒服,您也可能没有充分利用它们的潜力。 当然,没有义务学习更多关于 sedgrep 的知识,但我有时会思考我“学习”命令的方式。 我通常不是学习命令如何工作,而是学习包含命令的特定咒语。 因此,我经常对命令感到虚假的熟悉。 我认为我了解一个命令,因为我可以脱口而出说出三四个选项,即使我不知道这些选项的作用,也无法完全掌握语法。

我相信,这就是许多人在面对 awk 的强大功能和灵活性时遇到的问题。

学习 awk 以使用 awk

awk 的基础知识出奇地简单。 人们经常注意到 awk 是一种编程语言,虽然它是一种相对基础的语言,但这是事实。 这意味着您可以像学习新的编码语言一样学习 awk:使用一些基本命令学习其语法,学习其词汇表,以便您可以构建复杂的动作,然后练习、练习、再练习。

awk 如何解析输入

本质上,Awk 将输入视为一个数组。 当 awk 扫描文本文件时,它将每一行(单独且连续地)视为一个记录。 每个记录都分为字段。 当然,awk 必须跟踪这些信息,您可以使用内置变量 NR(记录数)和 NF(字段数)查看这些数据。 例如,这为您提供了文件的行数

$ awk 'END { print NR;}' example.txt
36

这也揭示了关于 awk 语法的一些信息。 无论您是将 awk 编写为单行代码还是独立的脚本,awk 指令的结构都是

pattern or keyword { actions }

在此示例中,单词 END 是一个特殊的保留关键字,而不是模式。 类似的关键字是 BEGIN。 对于这两个关键字,awk 只是在解析数据开始或结束时执行大括号中的操作。

您可以使用模式作为过滤器或限定符,以便 awk 仅在能够将您的模式与当前记录匹配时才执行给定的操作。 例如,假设您想使用 awk(就像使用 grep 一样)在文本文件中查找单词 Linux

$ awk '/Linux/ { print $0; }' os.txt
OS: CentOS Linux (10.1.1.8)
OS: CentOS Linux (10.1.1.9)
OS: Red Hat Enterprise Linux (RHEL) (10.1.1.11)
OS: Elementary Linux (10.1.2.4)
OS: Elementary Linux (10.1.2.5)
OS: Elementary Linux (10.1.2.6)

对于 awk,文件中的每一行都是一个记录,记录中的每个单词都是一个字段。 默认情况下,字段由空格分隔。 您可以使用 --field-separator 选项更改它,该选项将 FS(字段分隔符)变量设置为您想要的任何内容

$ awk --field-separator ':' '/Linux/ { print $2; }' os.txt 
 CentOS Linux (10.1.1.8)
 CentOS Linux (10.1.1.9)
 Red Hat Enterprise Linux (RHEL) (10.1.1.11)
 Elementary Linux (10.1.2.4)
 Elementary Linux (10.1.2.5)
 Elementary Linux (10.1.2.6)

在此示例中,每个列表前都有一个空格,因为源文本中每个冒号 (:) 后都有一个空格。 然而,这不是 cut,因此字段分隔符不必限制为一个字符

$ awk --field-separator ': ' '/Linux/ { print $2; }' os.txt 
CentOS Linux (10.1.1.8)
CentOS Linux (10.1.1.9)
Red Hat Enterprise Linux (RHEL) (10.1.1.11)
Elementary Linux (10.1.2.4)
Elementary Linux (10.1.2.5)
Elementary Linux (10.1.2.6)

awk 中的函数

您可以使用以下语法在 awk 中构建自己的函数

name(parameters) { actions }

函数很重要,因为它们允许您编写一次代码并在整个工作中重复使用它。 在构建单行代码时,自定义函数不如在脚本中那么有用,但 awk 已经为您定义了许多函数。 它们的工作原理与任何其他语言或电子表格中的任何函数基本相同:您学习函数需要从您那里获取信息的顺序,您可以向其提供任何您想要的内容以获得结果。

有执行数学运算和字符串处理的函数。 数学函数通常非常简单明了。 您提供一个数字,它会进行处理

$ awk 'BEGIN { print sqrt(1764); }'
42

字符串函数可能更复杂,但在 GNU awk 手册中有详细记录。 例如,split 函数接受 awk 视为单个字段的实体,并将其拆分为不同的部分。 它需要一个字段、一个用作数组的变量(包含拆分的每个部分)以及您要用作分隔符的字符。

使用前面示例的输出,我知道每个记录的末尾都有一个 IP 地址。 在这种情况下,我可以仅通过引用变量 NF 将记录的最后一个字段发送到 split 函数,因为它包含字段数(并且最后一个字段必须是最大的数字)

$ awk --field-separator ': ' '/Linux/ { split($NF, IP, "."); print "subnet: " IP[3]; }' os.txt
subnet: 1
subnet: 1
subnet: 1
subnet: 2
subnet: 2
subnet: 2

还有更多函数,并且没有理由将自己限制为每个 awk 代码块一个函数。 您可以在终端中使用 awk 构建复杂的管道,也可以编写 awk 脚本来定义和利用您自己的函数。

下载电子书

学习 awk 主要在于使用 awk。 即使这意味着复制您已经使用 sedgrepcuttr 或任何其他完全有效的命令实现的功能,也要使用它。 一旦您熟悉它,您可以编写 Bash 函数来调用您的自定义 awk 命令,以便更轻松地使用。 最终,您将能够编写脚本来解析复杂的数据集。

下载我们的电子书 ,了解您需要了解的关于 awk 的一切,并立即开始使用它。

接下来阅读什么
标签
Seth Kenlon
Seth Kenlon 是一位 UNIX 极客、自由文化倡导者、独立多媒体艺术家和 D&D 爱好者。 他曾在电影和计算机行业工作,而且经常同时工作。

1 条评论

非常感谢这篇文章。 我认为 Awk 比许多人意识到的更有用(也更强大),尤其是在 GNU Awk 5.0 (Gawk) 发布之后。 Gawk 中命名空间的添加意味着现在可以轻松构建函数库,以作为大型、结构良好的 Awk 程序的一部分调用。
Awk 是一种诱人的语言,一旦你花一些时间学习它。 对于我作为一名工程师来说,Awk 使得从文件中读取数据(即使是数百万行)变得非常简单,以至于我可以将时间集中在开发数据处理算法上。 我可能比现在任何其他语言都更多地使用 Awk 进行编程,这可能会引起一些人的惊讶。 如果需要,从 Awk 到 JavaScript(尤其是)的转换非常简单——几乎完全可以使用一些简单的正则表达式替换来实现。
Awk 可能很旧,但我认为它在过去几年中通过 Gawk 的改进而焕发了活力。 我已经爱上了 Awk!

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.