微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用包含 NULL 字符的正则表达式字符范围的 Grep

如何解决使用包含 NULL 字符的正则表达式字符范围的 Grep

当我在 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

解决方法

在 BSD grep 上,您或许可以使用:

LC_ALL=C grep -o '[[:print:][:cntrl:]]' <<< 'ABCabc<>/ă'

A
B
C
a
b
c
<
>
/

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

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

注意到 $'...' is a shell quoting construct,this,

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

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

您需要创建一些匹配 NUL 字节的模式,但不包括字面意思。但我认为 grep 不支持 \000\x00 转义本身。但是,Perl 会这样做,因此它会打印带有 NUL 的输入行:

$ printf 'foo\nbar\0\n' |perl -ne 'print if /\000/'
bar

顺便说一句,至少 GNU grep 似乎不喜欢那种范围表达式,所以如果你要使用它,你会做一些不同的事情。在 C 语言环境中,[[:cntrl:][:print:]]' 可能可以匹配从 \x01\x7f 的字符,但我没有进行全面检查。 manual for grep has some descriptions of the classes


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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。