awk重复{n}不起作用


18

我正在尝试使用重复符号{n}打印行,但是它不起作用。对于。例如我想打印所有长度为4个字符的行

 awk '/^.{4}$/' test_data

上面的代码没有打印出来。如何解决它,以便可以使用重复符号?我知道类似的选择awk '/^....$/' test_dataawk 'length ==3 ' test_data


3
您正在使用什么发行版?哪个awk?
terdon

1
$ awk --version GNU Awk 3.1.7 $ cat / etc / redhat-release红帽企业Linux服务器版本6.7(圣地亚哥)
永远的学习者

2
我想awk '/^.{4}+$/{print}' <<<$'foods\nbaarsz\nfooo' 精确匹配4个字符。就像您自己提到的那样, awk 'length($0) == 4' test_data它几乎与所有awk版本兼容。
Valentin Bajrami

4
难道awk --re-interval '/^.{4}$/' test_data 还是awk --posix '/^.{4}$/' test_data工作?
steeldriver'Mar

谢谢steeldriver。这解决了我的问题。已投票。再次感谢:)
永远的学习者2017年

Answers:


19

根据《 GNU Awk用户指南:功能历史》,在3.0版中添加了对正则表达式范围运算符的支持,但最初需要显式命令行选项

新的命令行选项:

  • 新的命令行选项:
    • --lint-old选项用于警告awk的原始版本7 Unix版本中不可用的构造(请参见V7 / SVR3.1)。
    • BWK awk的-m选项。(当时Brian仍在贝尔实验室。)后来又从他的awk和gawk中删除了。
    • --re-interval选项可在正则表达式中提供间隔表达式(请参阅正则表达式运算符)。
    • --traditional选项被添加为--compat的更好名称(请参阅选项)。

gawk4.0中

间隔表达式成为默认正则表达式的一部分

由于您使用的是gawk3.x,因此您需要使用

awk --re-interval '/^.{4}$/'

要么

awk --posix '/^.{4}$/'

或(感谢@StéphaneChazelas),如果您想要便携式的解决方案,请使用

POSIXLY_CORRECT=anything awk '/^.{4}$/'

(因为--posix--re-interval在其他awk实现中会导致错误)。


感谢Steeldriver,感谢您的宝贵时间和帮助。被投票并被接受为答案
永远的学习者

4
最好使用POSIXLY_CORRECT=anything awk '/^.{4}/'可移植代码(一个--posix--re-interval在其他awk实现中会导致错误)。
斯特凡Chazelas

尊敬的StéphaneChazelas,我发出命令$ POSIXLY_CORRECT = anything awk'/^.{4}/'test_data时,它打印了所有行。然后我意识到重复之后就没有最后的钱了。感谢您的投入。提出您的意见和解决方案。抱歉,由于重复操作后省略了$,我首先误解了它。
永远的学习者2017年

20

ERE(或使用的扩展正则表达式)最初没有。它最初是在BRE(由或使用)中引入的,但随着awkegrep{x,y}grepsed\{x,y\}语法不会破坏向后的可移植性。

但是,当使用这种{x,y}语法将其添加到ERE时,它确实破坏了向后的可移植性foo{2} RE之前已经匹配了其他内容。

因此,某些实现选择不这样做。您会发现/bin/awk/bin/nawk并且/bin/egrep在Solaris上仍然不兑现(您需要使用/usr/xpg4/bin/awk/usr/xpg4/bin/grep -E)。对于FreeBSD awknawk在FreeBSD上相同(基于Brian Kernighan(在中)awk维护)。kawk

对于GNUawk,直到最近(4.0版),您都必须对其进行调用POSIXLY_CORRECT=anything awk '/^.{4}$/'以兑现它。mawk仍然不兑现

请注意,该运算符只是语法糖。.{3,5}总是可以写....?.?(例如,当然{3,5}更容易读,而等效的情况(foo.{5,9}bar){123,456}会更糟)。


再次感谢StéphaneChazelas。抱歉,我不好,我最初无法理解您的答案。非常感谢并支持。
永远的学习者2017年

6

这可以与GNU awk(gawk)一起使用:

$ printf 'abcd\nabc\nabcde\n' | gawk '/^.{4}$/'
abcd

但是失败了mawk,它更接近POSIX,awk并且AFAIK是Ubuntu系统上的默认设置:

$ printf 'abcd\nabc\nabcde\n' | mawk '/^.{4}$/'
$ ## prints nothing

因此,一种简单的解决方案是使用gawk代替awk。该{n}符号不是POSIX BRE(基本正则表达式)语法的一部分。这就是为什么grep在这里也失败的原因:

$ printf 'abcd\nabc\nabcde\n' | grep '^.{4}$'
$

但是,它是ERE(扩展正则表达式)的一部分:

$ printf 'abcd\nabc\nabcde\n' | grep -E '^.{4}$'
abcd

我不知道mawkPOSIX或POSIX 使用哪种正则表达式样式awk,但我猜这是BRE。根据Stéphane的回答,他们使用ERE的较旧版本。无论如何,您可能正在使用的版本显然awk没有实现ERE,或者您的输入实际上没有任何包含正好4个字符的行。例如,这可能是由于您看不见的空白或Unicode字形造成的。


嗨,terdon,我想打印4个字符长的行。不是一行的前四个字符。例如,$ grep -E'^。{4} $'test_data可以工作,但同样不适用于awk
永远的学习者

@CppLearner是的,这就是我在这里所做的。你什么意思?
terdon

@ CppLearner,@ terdon的解决方案仅打印4个字符长的行。但是,如果您真的只对length($0)行长感兴趣,则应该使用比正则表达式更有效的代码。
史蒂芬·基特

嗨,老板,steeldriver的解决方案就是我想要的。谢谢你的时间。嗨,斯蒂芬·基特(Stephen Kitt),正如我在问题中提到的那样,我已经使用长度作为替代,我对从钢螺丝刀的注释中知道为什么重复正则表达式{n}不能正常工作更加感兴趣,我知道我需要使用--re-interval或--posix。谢谢你的时间。
永远的学习者

1
mawk并不是真的更接近POSIX awk,并且不使用BRE。它确实使用ERE,但没有{x,y}运算符。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.