awk 正则表达式中的界限在 OpenBSD 上不起作用

awk 正则表达式中的界限在 OpenBSD 上不起作用

此 awk 表达式inet 34.45在 OpenBSD 上按预期打印:

echo "inet 34.45" | awk '/inet [0-9]+\./ { print }'

但是,当我+用bound替换the时{1,3},我没有得到任何匹配:

echo "inet 34.45" | awk '/inet [0-9]{1,3}\./ { print }'

两种表达式都可以在 Linux 上使用 gawk 正常工作。 gawk 手册页提到,awk 最初不支持它所谓的间隔表达式,但后来添加到 POSIX 中以与egrep 保持一致。 OpenBSD 上的 awk 手册页没有提到这样的事情,只是引用了 re_format 的手册页,它像往常一样指定了边界。

这是 OpenBSD awk 的错误还是某些未记录的限制?

答案1

该限制有明确记录。

从:http://man.openbsd.org/awk.1#STANDARDS

标准

awk 实用程序符合 IEEE Std 1003.1-2008 (“POSIX.1”) 规范,但 awk 不支持 {n,m} 模式匹配。

答案2

我不能为 OpenBSD 的人们提供担保,但有一个理由限制 /区间表达式OpenBSD 和大多数其他 awk 实现不支持可能因为他们是可怕的烂摊子,实施方面。

我将从一个测试用例开始,使用 GNU awk ( gawk),它支持它们:

time echo | gawk '/a{1,30000}/'
  # still going strong, after 5 minutes with the CPU at 100%
  # and eating up > 4G of memory

因为 awk 正在使用真实的正则表达式(状态机/有限自动机类型,而不是 Perl 的递归/回溯空间和时间无界类型),计数重复只能通过静态重复正则表达式子表达式在代码中,根据需要多次。

正则表达式 like实际上在编译时a{1,4}变成了类似的东西。a(a(aa?)?)?你可以很容易地看出这有多么令人讨厌,但除了非常小重复次数:即使是很小的重复次数也/a{1,500}/需要半秒和许多 MB 的内存。


尽管 POSIX 强制要求,截至 2020 年 4 月,Debian 10 (Buster)、OpenBSD 6.6 和 FreeBSD 12.1 以及 Solaris 11 的默认 awk 不支持间隔表达式。/usr/bin/nawk除了 Debian(正在使用mawk)之外,所有其他基于传统的 nawk(“新 awk”)。

除了 GNU awk 之外,支持区间表达式的 awk 实现还有 busybox awk 以及 NetBSD 和 MacOS 中的默认 awk。

据称是诺克的后裔(布克,“一个真正的 awk”)最近也包括支持区间表达式,恕我直言,这一举动绝对没有经过深思熟虑。

POSIX 历史上曾对 awk 强制要求被破坏的要求,然后这些要求就必须被淘汰;一个例子是0=="000"应评估为 1(真)的要求,即掉落在当前版本的标准中,但不幸的是它已从/usr/xpg4/bin/awkSolaris 进入,使其无法使用。

相关内容