此 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/awk
Solaris 进入,使其无法使用。