为什么grep
macOS 上的 BSD 只生成这里的第一个单词:
$ echo "once upon a time" | grep -o "[a-z]*"
once
但这里所有的话:
$ echo "once upon a time" | grep -o "[a-z][a-z]*"
once
upon
a
time
或者,使用扩展正则表达式:
$ echo "once upon a time" | grep -E -o "[a-z]*"
once
$ echo "once upon a time" | grep -E -o "[a-z]+"
once
upon
a
time
GNUgrep
将为[a-z]+
(或[a-z][a-z]*
) 和产生相同的输出[a-z]*
:
$ echo "once upon a time" | ggrep -E -o "[a-z]*"
once
upon
a
time
$ echo "once upon a time" | ggrep -E -o "[a-z]+"
once
upon
a
time
答案1
收集评论部分的想法,这似乎归结为不同的grep
实现决定如何处理空匹配以及[a-z]*
空字符串上的表达式匹配。
该-o
选项不是由 POSIX 定义的,因此实现方式如何处理它留给开发人员。
GNUgrep
显然会丢弃空匹配,例如once
使用 时后面的空字符串的匹配[a-z]*
,并继续从下一个字符开始处理输入。
BSDgrep
似乎正在打空火柴,并决定,无论出于何种原因,这已经足够了,并就此停止。
Stéphane 提到,ast-open
的版本实际上在aftergrep
的空匹配处进入无限循环,并且不会超过字符串中的该点。[a-z]*
once
OpenBSDgrep
似乎与 macOS 和 FreeBSD 不同,grep
因为添加-w
标志(要求匹配由单词边界分隔)使得[a-z]*
单独返回每个单词。
ilkkachu 观察到,-o
在某种意义上允许匹配空字符串的模式是令人困惑的(或者可能至少是不明确的)。是否应该打印所有空匹配项?事实上,给定字符串中的每个单词后面都有无限多个这样的匹配。
OpenBSD 源代码grep
(表现出与 macOS 上相同的行为grep
)包含 (src/usr.bin/grep/util.c
):
if (r == 0) {
c = 1;
if (oflag && pmatch.rm_so != pmatch.rm_eo)
goto print;
break;
}
}
if (oflag)
return c;
print:
这基本上是说,如果模式匹配 ( r == 0
) 并且我们使用-o
( oflag
),并且如果匹配开始偏移量与匹配结束偏移量相同(pmatch.rm_so == pmatch.rm_eo
,即空匹配),则匹配结果为不是打印并且此特定输入行的匹配结束(return c
表示c == 1
“找到匹配”)。