我试图理解为什么grep -w
(GNU 实现的版本 3.1)仅匹配一行中特定模式的第一次出现。
这是一个例子。我希望它会匹配n1
,n2
和n3
,但它只匹配第一个。
$ echo 'n1=1 n2=2 n3=3' | grep -ow "n[0-9]=*"
n1
或者,如果我告诉它仅匹配n2
或n3
,它再次匹配第一个,并忽略n3
。
$ echo 'n1=1 n2=2 n3=3' | grep -ow "n[23]=*"
n2
我在这里缺少什么?对于这种行为有任何解释吗,或者这是 grep 中的某种错误?
这个想法是匹配:
n[0-9]
前面和后面都是非单词字符。n[0-9]
以 开头,后跟任意数量的=
字符,以非单词字符结尾的子字符串。
例如,如果字符串是n1=1 n2=== n3=3 n4== n5
,则预期结果应该是:
n1
n2===
n3
n4==
n5
澄清:我知道这个目标可以实现grep -ow -e 'n[0-9]' -e "n[0-9]=*"
,但这不是重点。该问题的目的是了解如何grep
工作。
加法测试
如果我添加n<num>=
到行中的不同位置(等号后没有后续单词字符),它也会匹配这些字符,但它会再次忽略n3=3
.
$ echo 'n1=1 n2= n3=3 n4=' | grep -ow "n[0-9]=*"
n1
n2=
n4=
我发现的最后一件事是,如果我添加将-P
模式解释为 Perl 兼容的正则表达式,它似乎不会保留-w
子字符串的描述“必须位于行尾或后跟非单词组成字符”,因为n1=
即使后面跟着字符,它也会匹配1,这是一个单词组成字符(“字母、数字和下划线”)。
$ echo 'n1=1 n2= n3=3 n4=' | grep -owP "n[0-9]=*"
n1=
n2
n3=
n4
所以看起来grep -wP
搜索字边界在子字符串的末尾而不是非单词组成字符。它似乎相当于:
$ echo 'n1=1 n2= n3=3 n4=' | grep -o "\bn[0-9]=*\b"
n1=
n2
n3=
n4
答案1
接得好。这似乎确实是一个错误grep
(用 3.4 和 3.7 测试GNU grep
):
grep -ow "n[0-9]=*"
grep -Eow "n[0-9]=*"
仅返回第一个匹配项(或者可能只匹配第一个匹配项),
而...
grep -Pow "n[0-9]=*"
...按预期返回所有匹配项。
要报告 的错误GNU grep
,请检查这里。
然而,我无法证实你的观察-P
[...]似乎没有保留-w
描述,对我来说(GNU grep 3.4 和 3.7),该命令按预期输出:
$ echo 'n1=1 n2= n3=3 n4=' | grep -owP "n[0-9]=*"
n1
n2=
n3
n4=
答案2
例如,如果字符串是
n1=1 n2=== n3=3 n4== n5
,则预期结果应该是:n1 n2=== n3 n4== n5
澄清:我知道可以通过以下方式实现该目标
grep -ow -e 'n[0-9]' -e "n[0-9]=*"
对此也不太确定:
u$ grep --version |head -1
grep (GNU grep) 2.27
u$ printf '%s\n' 'n1=1 n2=== n3=3 n4== n5' | grep -ow -e 'n[0-9]' -e "n[0-9]=*"
n1
n2===
n3
n4==
n5
与
a$ grep --version |head -1
grep (GNU grep) 3.4
a$ printf '%s\n' 'n1=1 n2=== n3=3 n4== n5' | grep -ow -e 'n[0-9]' -e "n[0-9]=*"
n1
n2===
n4==
n5
n3
请注意较新的 grep 是如何缺失的。这是在Ubuntu上,结果与3.7相同。
而对于 Busybox,答案又不同了:
$ printf '%s\n' 'n1=1 n2=== n3=3 n4== n5' | busybox grep -ow -e 'n[0-9]' -e "n[0-9]=*"
n1
n2
n3
n4
n5
我的 Mac 上的 BSD grep 也会打印n1
, n2
... 等,但每个打印两次。无论出于何种原因。
喜欢斯特凡在评论中说,用于-w
此目的似乎不便携。
这个想法是匹配:
n[0-9]
前面和后面都是非单词字符。
n[0-9]
以 开头,后跟任意数量的=
字符,以非单词字符结尾的子字符串。
在我看来,您想要在 Perl 中实现类似的功能(按此顺序,以便=
具有优先权):
/ n[0-9]=*(?=\W) | \bn[0-9]\b /x
例如
$ printf '%s\n' 'n1=1 n2=== n3=3 n4== n5' |
perl -lne 'print $& while / n[0-9]=*(?=\W) | \bn[0-9]\b /xg'
n1
n2===
n3
n4==
n5
但我不确定这是否是您想要的。如果它n2===x
代替n2===
,则输出为n2==
,因为最后一个=
用于满足“以非单词字符结尾”子句。 (或者更确切地说,“后面是”,否则 for 的匹配也n1=1
应该是n1=
。那就是n1
,后跟零=
s,后跟非单词字符=
。)
我认为你可以使用所有格量词=*+
来避免返回任何符号=
,所以:
$ printf '%s\n' 'n1=1 n2===X n3=3 n4== n5' |
perl -lne 'print $& while / n[0-9]=*+(?=\W) | \bn[0-9]\b /xg'
n1
n2
n3
n4==
n5
无论如何,我想知道通过简单的逻辑是否可以更好地实现您想要做的事情,即仅在空格上拆分字符串,在符号上拆分子字符串=
,然后查看各个值。