GNU Awk 4.1:老鸟学新招,第二部分

在之前的一篇文章(“GNU Awk 4.0:老鸟学新招”,发表于 2011 年 9 月刊的Linux Journal)中,我简要介绍了 awkgawk 的历史,并对 gawk 4.0 中的许多新功能进行了高层次的概述。我建议您先阅读那篇文章,当然,如果您愿意,也可以不读那篇文章直接阅读这篇。

gawk 4.0 本身于 2011 年 6 月发布。自那时以来,gawk 开发团队并没有止步不前!gawk 4.1 于 2013 年 5 月发布,包含许多新功能,这就是我在此处要介绍的内容。

gawk 4.0 不同,这次在语言层面的更改要少得多(尽管仍然有一些)。这次的更改更多地关注内部机制以及与外部世界交互的能力。那么,让我们开始吧。

减少占用空间

多年来,当您构建 gawk 时,您会得到两个可执行文件:常规解释器 gawk 和其性能分析孪生兄弟 pgawk,后者运行 awk 程序(速度较慢)并生成语句计数执行配置文件,显示每行代码执行了多少次。

gawk 4.0 中,您又获得了一个额外的可执行文件 dgawk,即 gawk 调试器。尽管这三个版本共享了大部分相同的代码,但实际执行 awk 程序的内核部分在每个版本中都是以不同的方式编译的。

对于 gawk 4.1,所有三个可执行文件都已合并到一个名为 gawk 的程序中。尽管合并后的可执行文件更大,但它仍然比拥有三个独立的可执行文件要小,此外,文档也更简单易懂(且易于维护!)。

为了适应此更改,选项必须稍作更改。您现在可以使用 -D 运行调试器,使用 -p 进行性能分析,使用 -o 进行美化打印而不进行性能分析。

使用 MPFR 和 GMP 的任意精度算术

对于 awk 程序员来说,一个重要的新功能是使用 GNU MPFR 和 GMP 库进行任意精度浮点算术。

这是一个可选功能:如果您在配置和构建 gawk 时安装了 MPFR 和 GMP 库,则 gawk 将自动能够使用它们。

请注意,我说的是“能够使用它们”。您仍然必须选择使用 -M 选项(或 --bignum,如果您喜欢长选项),或者将特殊变量 PREC 设置为所需的浮点精度。

精度是浮点尾数中保留的位数。默认值为 53,这与硬件双精度浮点数使用的精度相同。摘自 gawk 手册


$ gawk -M -v PREC=100 'BEGIN { x = 1.0e-400; print x + 0}
> PREC = "double"; print x + 0 }'
1e-400
0

您会看到常规硬件无法处理 -400 的指数,而 MPFR 可以。

另一个新的变量 ROUNDMODE 设置了计算和打印任意精度值的舍入模式。

在过去的几年中,由于一些我不太明白的原因,我收到了人们的错误报告,他们期望 gawk 的算术运算与用纸和笔进行的“真实”算术运算完全相同。换句话说,他们想要计算机科学中所谓的十进制算术。我不确定他们为什么期望这样,但正如我们都应该知道的那样,计算机并非完全以这种方式工作。

MPFR 不会为您提供十进制算术。但是,如果您了解自己在做什么以及如何使用它,您可以获得可能足以满足您目的的结果。

该手册有一整章描述了与浮点算术相关的问题,增加精度意味着什么,以及如何使用 MPFR 支持的各种舍入模式。

新数组提供间接变量访问

有三个新数组

  • SYMTAB:提供对 awk 级别变量的访问。

  • FUNCTAB:列出所有用户定义函数和扩展函数的名称。

  • PROCINFO["identifiers"]:列出所有已知的标识符以及 gawk 在解析程序后了解的其类型。

其中,SYMTAB 最有趣,因为它提供了对任何变量的间接访问。例如


$ gawk 'BEGIN { a = 5 ; print "a =", a
> SYMTAB["a"] += 37
> print "a is now", a }'
a = 5
a is now 42

使用 isarray() 内置函数,您可以“遍历”整个符号表并打印出所有变量和数组值(如果您选择这样做)。

动态扩展

gawk 4.1 中最令人兴奋的改变是其与外部世界交互的能力。多年来,gawk 具有一种“扩展”或“插件”机制,允许程序员用 C 语言编写新的“内置”函数,并在运行时将其加载到正在运行的 gawk 解释器中。

这种机制需要了解一些 gawk 的内部机制,并利用 gawk 的内部数据结构和函数。尽管文档记录很少,并且它可以工作,但它有几个缺点。最显着的缺点是跨版本没有向后兼容性。

尽管如此,一组开发人员还是 fork 了 gawk 以创建 xgawk (XML gawk),并为核心可执行文件开发了许多动态扩展和新功能。

多年来,我一直想为编写扩展提供定义的 C API,该 API 不依赖于 gawk 内部机制,并且可能在不同版本之间提供二进制兼容性。

对于 gawk 4.1,我们与 xgawk 开发人员一起,最终实现了这一点。

为什么需要扩展?

考虑一下:awk 程序甚至无法使用 chdir 系统调用来更改其工作目录!因此,awk 是一种封闭的语言——一种仅为您提供实现者选择提供的功能,仅此而已。这没什么乐趣。(好吧,awk 很有趣,但它仍然有限。)

相比之下,现代脚本语言都是开放且可扩展的;Perl、Tcl、Python 和 Ruby 都拥有数千个可在运行时加载的可用模块。gawk 也应该能够做到这一点,这已经过时了。

您可以从扩展中做什么

最好将扩展函数视为用另一种语言编写的用户定义函数。它们不能做用户定义函数可以做的所有事情(例如调用 awk 函数、操作字段、使用 getline 读取记录等等),但它们可以做的事情足以使 gawk 更加开放,并使其与底层操作系统和其他 C(或 C++)库接口。特别是,您可以

  • 按值传递标量,按引用传递数组。

  • 创建和修改新的全局变量和数组。

  • 访问内置变量(只读,尽管您可以更新 PROCINFO)。

  • 注册一个在 gawk 退出时调用的函数。

  • 打印警告和/或致命错误消息。

  • 更新内置变量 ERRNO 以在出现问题时使用。

  • Hook 进入 I/O 重定向机制,提供您自己的“特殊”文件名和/或双向通信器。

  • 当然,注册可以从 gawk 调用的新函数。

API 提供了许多数据类型,以便更轻松地与 gawk 通信。例如,gawk 字符串可以包含嵌入的 NUL 字符(所有位均为零),因此字符串具有指针和长度。gawk 在内部维护引用计数的字符串,因此有方法告诉 gawk 重用它已经知道的值。

此外,API 允许您将 awk 的关联数组“展平”为结构数组,以便在 C 代码中轻松迭代,而无需在每次想要移动到数组中的下一个元素时都调用 gawk

API 的完整描述超出了本文的范围;但是,该手册包含一整章,其中包含示例,描述了 API 并展示了如何使用它。

操作系统独立性

扩展机制旨在在多个操作系统上工作。在撰写本文时,它可以在任何支持 POSIX dlopen() API 的 *nix 系统上工作。这包括 Mac OS X。基本机制也适用于使用 MinGW 的 Microsoft Windows。但是,由于尚未准备就绪,因此 4.1 版本中未包含构建示例扩展的支持。此支持将包含在第一个补丁版本中,无论何时发布,尽管并非所有示例扩展都可以在 Windows 上工作。

示例扩展

gawk 发行版提供了许多小型示例扩展。它们的主要目的是作为如何使用 API 的示例,但尽管如此,它们也应该可以用于实际工作。完整列表在手册中有所记录。一些更有趣的包括

  • “filefuncs”扩展,提供 chdir()stat() 函数,以及 fts(3) 例程套件的接口,用于遍历文件层次结构。

  • “fnmatch”扩展,提供 fnmatch(3) 套件的 awk 版本。

  • “readdir”扩展,它为 gawk 命令行上命名的目录或使用 getline 读取的目录返回内容记录。(通常,尝试读取目录是非致命错误。对于其他 awks,这是致命的。)

  • “inplace”扩展,它模拟 GNU sed -i 功能,用于就地编辑命令行数据文件。

其他更专业的扩展说明了 API 的某些部分的使用,这些部分未在刚刚列出的扩展中涵盖。

gawkextlib 项目

现在 gawk 支持主要的 xgawk 功能,xgawk 开发人员已将其项目围绕其特定扩展进行了重新定位。它不再包括 fork 的 gawk 代码库。为了强调这种方向的改变,他们将其项目重命名为“gawkextlib”。

他们(和我的)希望该项目可以作为 awk 社区随着时间的推移可能编写的新 gawk 扩展的中央信息交换中心。

gawkextlib 项目目前有四个扩展

  • XML 扩展,它添加了几个新变量和一个输入解析器,使 gawk 能够以自然的方式解析 XML 文件。此扩展构建在 Expat XML 解析器之上。这是一个强大的扩展;您不必尝试手动使用正则表达式解析 XML 文件,Expat 解析器会为您完成,包括所有在纯 awk 代码中很难完成的令人讨厌的验证工作。

  • PostgreSQL 扩展,它提供了与 PostgreSQL 数据库通信的函数。

  • GD 图形库扩展,用于 GD 图形库(请参阅资源)。

  • MPFR 库扩展。此扩展使您可以访问许多无法从 gawk 的内置 MPFR 支持访问的 MPFR 函数。

未来

我觉得 gawk 作为一种语言已经基本成熟,并且不希望添加太多新功能。也就是说,仍然有一些项目有待探索

  • 额外的数字功能,例如可能与十进制算术库集成。

  • 一种将 gawk 数组映射到外部存储的方法,例如 DBM 数组或 SQL 数据库。

  • 扩展函数和变量以及可能的常规 gawk 级别变量和函数的“命名空间”功能。这将是一项重大的设计活动。

当然,描述上述项目并不构成承诺要执行其中任何一项。

结论

新的 API 和扩展工具为 gawkawk 程序员开辟了新的视野。我对此感到非常兴奋,并且我希望看到 gawk 被用于许多以前根本不适用的新事物。

致谢

感谢 Scott Deifik、Brian W. Kernighan 博士、Nelson Beebe 博士和 Eli Zaretskii 对本文初稿的评论。

整个 gawk 开发团队都值得称赞他们为这个版本所做的工作。这在很大程度上是一项团队努力。

资源

“GNU Awk 4.0:老鸟学新招”,LJ,2011 年 9 月:http://www.linuxjournaldigital.com/linuxjournal/201109#pg94

gawk 发行版:http://ftp.gnu.org/gnu/gawk/gawk-4.1.0.tar.gz

在线文档:https://gnu.ac.cn/software/gawk/manual

使用 gawk 的任意精度算术:https://gnu.ac.cn/software/gawk/manual/html_node/Arbitrary-Precision-Arithmetic.html#Arbitrary-Precision-Arithmetic

动态扩展:https://gnu.ac.cn/software/gawk/manual/html_node/Dynamic-Extensions.html#Dynamic-Extensions

gawkextlib 主页:http://gawkextlib.sourceforge.net

gawkextlib 下载:http://sourceforge.net/projects/gawkextlib

GD 图形库:http://www.boutell.com/gd/manual2.0.33.html

Expat XML 解析器:http://expat.sourceforge.net

加载 Disqus 评论