在所有 Linux 命令中(有很多),最典型的三个似乎是 sed
、awk
和 grep
。 也许是它们名字的神秘感,或者是它们潜在用途的广泛性,或者仅仅是它们的年代久远,但当有人举例说明“Linux 式”命令时,通常是这三个命令之一。 虽然 sed
和 grep
有几个简单的一行标准,但不太知名的 awk
仍然因其特别令人费解而一直突出。
您很可能每天使用 sed
进行快速字符串替换,或使用 grep
过滤模式。 您不太可能编写 awk
命令。 我经常想知道这是为什么,我将其归因于以下几点。 首先,我们中的许多人很少使用 sed
和 grep
,除了这两个命令的一些变体之外
$ sed -e 's/foo/bar/g' file.txt
$ grep foo file.txt
因此,即使您可能对 sed
和 grep
感到更舒服,您也可能没有充分利用它们的潜力。 当然,没有义务学习更多关于 sed
或 grep
的知识,但我有时会思考我“学习”命令的方式。 我通常不是学习命令如何工作,而是学习包含命令的特定咒语。 因此,我经常对命令感到虚假的熟悉。 我认为我了解一个命令,因为我可以脱口而出说出三四个选项,即使我不知道这些选项的作用,也无法完全掌握语法。
我相信,这就是许多人在面对 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
。 即使这意味着复制您已经使用 sed
或 grep
或 cut
或 tr
或任何其他完全有效的命令实现的功能,也要使用它。 一旦您熟悉它,您可以编写 Bash 函数来调用您的自定义 awk
命令,以便更轻松地使用。 最终,您将能够编写脚本来解析复杂的数据集。
1 条评论