awk 中的行为不一致

awk 中的行为不一致

我有一个名为的文本文件junk.txt

hello
foo
0
-1
0
1
0
2
0
foo

Cindy
00000

Lou
2 000
0
Who
0000
0
wat?
0000 00000
0
0
0000 00000

filler

00

0
00
000
0000
0

0
bye

当我运行以下命令时,我得到:

cat junk.txt | awk '{if (/foo/ ~ $1) print $1,"<-- found match"; else print $1}'
awk: cmd. line:1: warning: regular expression on left of `~' or `!~' operator
hello
foo
0 <-- found match
-1
0 <-- found match
1
0 <-- found match
2
0 <-- found match
foo
 <-- found match
Cindy
00000
 <-- found match
Lou
2
0 <-- found match
Who
0000
0
wat?
0000
0
0
0000
 <-- found match
filler
 <-- found match
00
 <-- found match
0 <-- found match
00 <-- found match
000 <-- found match
0000 <-- found match
0 <-- found match
 <-- found match
0 <-- found match
bye

我明白当正则表达式位于 的左侧时会发生什么~

我知道一个0或一个空字符串(null?)将被视为匹配。

我不明白的是为什么有时 a 0will 匹配,有时则不匹配。看起来它与之前处理的任何记录有关,但我认为awk独立处理每个输入记录,因此它们不应该相互影响(至少在没有一些变量分配或其他操作的情况下)。

编辑:如果重要的话我正在使用 GNU Awk 4.1.3

答案1

来自 (g)awks 手册页:

~ !~        Regular expression match, negated match.  NOTE: Do not use a constant regular  expression  (/foo/)
            on  the left-hand side of a ~ or !~.  Only use one on the right-hand side.  The expression /foo/ ~
            exp has the same meaning as (($0 ~ /foo/) ~ exp).  This is usually not what you want.

如果您以明确告诉您不要的方式使用它,您预计会发生什么?

答案2

事实上,这是一个有趣的问题。 @tink 指出了为什么你的代码不能按预期工作,但这不是问题。问题是“为什么0有时会匹配”。

如果(/foo/ ~ $1)确实意味着(($0 ~ /foo/) ~ $1)($0 ~ /foo/)则将评估1该行是否包含foo0否则。因此,您(主要)正在评估0 ~ $1.如果输入行为空,则$1 == ""、 和空正则表达式始终匹配。如果输入行恰好为0,则$1和 也0 ~ 0为 true。000例如,如果输入行是,那么 也是$1,并且0 ~ 000不应该为真。但是,很可能会在检查匹配之前将其000转换为。0

但不幸的是,这个解释并没有涵盖所有情况。

情况1

0 <-- found match
a
0 <-- found match
0 <-- found match

这完全符合预期。

案例2

0 <-- found match
00 00 <-- found match
0 <-- found match

这也是预期的,只要任意数量的零都被解释为0。但现在,这个:

案例3

0 <-- found match
a
00 0
0

这不能这么简单地解释掉。匹配失败后,似乎不会发生到零的转换,并且后面应该匹配的行也不会发生。

案例4

0 <-- found match
a
00 00
a
0 <-- found match

无论发生什么,另一次失败的匹配似乎会将awk的行为重置为正常,并且匹配再次按预期进行。

总而言之,GNU 手册页中的解释(awk顺便说一下,它不是信息页的一部分)是不正确的(或者至少是不完整的),或者程序包含错误。

相关内容