Grep使用包含NULL字符的regex字符范围



当我在BSD grep中的regex字符范围中包含NULL字符(x00)时,结果是意外的:没有字符匹配。为什么会发生这种情况?

下面是一个例子:

$ echo 'ABCabc<>/ă' | grep -o [$'x00'-$'x7f']

这里我希望所有字符直到最后一个匹配,然而结果是没有输出(没有匹配)。

或者,当我从x01开始字符范围时,它按预期工作:

$ echo 'ABCabc<>/ă' | grep -o [$'x01'-$'x7f']
A
B
C
a
b
c
<
>
/

还有,这里是我的grep和BASH版本:

$ grep --version
grep (BSD grep) 2.5.1-FreeBSD
$ echo $BASH_VERSION
3.2.57(1)-release

在BSDgrep上,您可以使用:

LC_ALL=C grep -o '[[:print:][:cntrl:]]' <<< 'ABCabc<>/ă'
A
B
C
a
b
c
<
>
/

或者您可以使用home brew包安装gnu grep并运行:

grep -oP '[[:ascii:]]' <<< 'ABCabc<>/ă'

注意$'...'是一个shell引用结构,因此,

$ echo 'ABCabc<>/ă' | grep -o [$'x00'-$'x7f']

将尝试将文字NUL字符作为命令行参数的一部分传递给grep。这在任何类unix系统中都不可能做到,因为命令行参数是作为以空结束的字符串传递给进程的。因此,实际上,grep只看到参数-o[

您需要创建一些匹配NUL字节的模式,而不需要从字面上包含它。但我不认为grep支持00x00转义本身。但是Perl会这样做,所以这会输出带有NUL的输入行:

$ printf 'foonbarn' |perl -ne 'print if /00/'
bar

作为题外话,至少GNU grep似乎不喜欢这种范围表达式,所以如果要使用它,您需要做一些不同的事情。在C语言环境中,[[:cntrl:][:print:]]'可能会匹配x01x7f的字符,但我没有全面检查。grep的手册中有一些类的描述。


还要注意[$'x00'-$'x7f']有一对未加引号的[],因此是shell glob。这与NUL字节无关,但是如果您的文件匹配glob(任何一个字母的名称,如果glob在您的系统上工作——它在我的Linux上不起作用),或者设置了failglobnullglob,那么它可能会给出您不想要的结果。相反,把括号也括起来:$'[x00-x7f]'.

最新更新