使用包含 NULL 字符的正则表达式字符范围进行 Grep
Grep with a regex character range that includes the NULL character
当我在 BSD grep 的正则表达式字符范围内包含 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
注意到$'...'
is a shell quoting construct,这个,
$ echo 'ABCabc<>/ă' | grep -o [$'\x00'-$'\x7f']
会尝试将文字 NUL 字符作为命令行参数的一部分传递给 grep
。这在任何类 Unix 系统中都是不可能的,因为命令行参数作为以 NUL 结尾的字符串传递给进程。所以实际上,grep
只看到参数 -o
和 [
.
您需要创建一些匹配 NUL 字节的模式,而不是按字面意思包含它。但我认为 grep
不支持 [=18=]0
或 \x00
逃逸本身。不过,Perl 确实如此,因此它会打印带有 NUL:
的输入行
$ printf 'foo\nbar[=11=]\n' |perl -ne 'print if /[=11=]0/'
bar
顺便说一句,至少 GNU grep 似乎不喜欢那种范围表达式,所以如果你要使用它,你需要做一些不同的事情。在 C
语言环境中,[[:cntrl:][:print:]]'
可能会匹配从 \x01
到 \x7f
的字符,但我没有全面检查。
manual for grep has some descriptions of the classes.
另请注意,[$'\x00'-$'\x7f']
有一对未加引号的 [
和 ]
,shell 也是如此。这与 NUL 字节无关,但是如果你有匹配 glob 的文件(任何一个字母的名称,如果 glob 在你的系统上工作——它不在我的 Linux 上),或者有failglob
或 nullglob
集,它可能会产生您不想要的结果。相反,也引用括号:$'[\x00-\x7f]'
.
在 BSD grep
上,您可以使用这个:
LC_ALL=C grep -o '[[:print:][:cntrl:]]' <<< 'ABCabc<>/ă'
A
B
C
a
b
c
<
>
/
或者您可以使用 home brew
软件包和 运行:
安装 gnu grep
grep -oP '[[:ascii:]]' <<< 'ABCabc<>/ă'
当我在 BSD grep 的正则表达式字符范围内包含 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
注意到$'...'
is a shell quoting construct,这个,
$ echo 'ABCabc<>/ă' | grep -o [$'\x00'-$'\x7f']
会尝试将文字 NUL 字符作为命令行参数的一部分传递给 grep
。这在任何类 Unix 系统中都是不可能的,因为命令行参数作为以 NUL 结尾的字符串传递给进程。所以实际上,grep
只看到参数 -o
和 [
.
您需要创建一些匹配 NUL 字节的模式,而不是按字面意思包含它。但我认为 grep
不支持 [=18=]0
或 \x00
逃逸本身。不过,Perl 确实如此,因此它会打印带有 NUL:
$ printf 'foo\nbar[=11=]\n' |perl -ne 'print if /[=11=]0/'
bar
顺便说一句,至少 GNU grep 似乎不喜欢那种范围表达式,所以如果你要使用它,你需要做一些不同的事情。在 C
语言环境中,[[:cntrl:][:print:]]'
可能会匹配从 \x01
到 \x7f
的字符,但我没有全面检查。
manual for grep has some descriptions of the classes.
另请注意,[$'\x00'-$'\x7f']
有一对未加引号的 [
和 ]
,shell 也是如此。这与 NUL 字节无关,但是如果你有匹配 glob 的文件(任何一个字母的名称,如果 glob 在你的系统上工作——它不在我的 Linux 上),或者有failglob
或 nullglob
集,它可能会产生您不想要的结果。相反,也引用括号:$'[\x00-\x7f]'
.
在 BSD grep
上,您可以使用这个:
LC_ALL=C grep -o '[[:print:][:cntrl:]]' <<< 'ABCabc<>/ă'
A
B
C
a
b
c
<
>
/
或者您可以使用 home brew
软件包和 运行:
gnu grep
grep -oP '[[:ascii:]]' <<< 'ABCabc<>/ă'