我试图查找两个块设备上以字符开头#
、介于 1635700000 和 1653699999 之间、以空字符 ( \0
) 或 Linux 换行符 ( \0xA
) 结尾的所有数字。
我想出的这个grep
肯定不优雅:
grep --only-matching --byte-offset --text -Pa '#1635[7-9][0-9]{5}(\x0|$)|#163[6-9][0-9]{6}(\x0|$)|#164[0-9]{7}(\x0|$)|#165[0-2][0-9]{6}(\x0|$)|#1653[0-6][0-9]{5}(\x0|$)' /dev/device
尽管不能像这样输入和执行它,但这里有相同的语句和一些换行符,以使其更具可读性。
grep --only-matching --byte-offset --text -Pa '
#1635[7-9][0-9]{5}(\x0|$)
|#163[6-9][0-9]{6}(\x0|$)
|#164[0-9]{7}(\x0|$)
|#165[0-2][0-9]{6}(\x0|$)
|#1653[0-6][0-9]{5}(\x0|$)
' /dev/device
这在其中一个块设备上有效,但在另一个块设备上,在一些但不是全部输出之后,它停止并出现错误:
grep: exceeded PCRE's line length limit
我猜测失败的块设备有较长的字节,没有\0
or\0xA
字符,超过了行长度限制阈值。
因此,我尝试将 NULL 字符更改为换行符:
sed 's/\x0/\n/g' /dev/device | grep ...
但是,它因大约相同的原因而停止:
sed: regex input buffer length larger than INT_MAX
如何在第二个块设备上找到我想要查找的内容?很确定它需要是一个不同的实用程序,要么使用更大的输入缓冲区,要么不读取整行,甚至可能是一个自定义的 perl/python/C/C++ 程序。
我确实需要输出为每个找到的匹配一行,包括找到的字节偏移量和数量。
修改块设备不是一个选项。将会有数以万计的结果,因此在十六进制编辑器之类的工具中手动搜索也不是一个选择。
答案1
在上面的评论中,@terdon 给出了有关首先减少搜索空间的关键见解。通过使用扩展的 grep 模式语法来减少 Perl (PCRE) grep 模式语法的最大行长度,我能够让它工作。
grep --only-matching --byte-offset --text -E '#[0-9]{10}.' /dev/device | grep --only-matching --text -P '[0-9]*:#1635[7-9][0-9]{5}(\x0|$)|[0-9]*:#163[6-9][0-9]{6}(\x0|$)|[0-9]*:#164[0-9]{7}(\x0|$)|[0-9]*:#165[0-2][0-9]{6}(\x0|$)|[0-9]*:#1653[0-6][0-9]{5}(\x0|$)' /dev/device
尽管不能像这样输入和执行它,但这里有相同的语句和一些换行符,以使其更具可读性。
grep --only-matching --byte-offset --text -E
'#[0-9]{10}.'
/dev/device
| grep --only-matching --text -P '
[0-9]*:#1635[7-9][0-9]{5}(\x0|$)
|[0-9]*:#163[6-9][0-9]{6}(\x0|$)
|[0-9]*:#164[0-9]{7}(\x0|$)
|[0-9]*:#165[0-2][0-9]{6}(\x0|$)
|[0-9]*:#1653[0-6][0-9]{5}(\x0|$)
' /dev/device
扩展的 grep 模式语法引擎没有我遇到的行长度限制,并且减少了给予 perl (PCRE) 模式语法引擎的最大行长度。
答案2
以下是使用 bash(1)、grep(1) 和 perl(1) 的解决方案:
1 #!/bin/bash
2 grep -P -a -b -o '#\d{10}(\000|$)' \
3 | perl -ne '/(\d{10})/; print if 1635700000 <= $1 && $1 <= 1653699999' \
4 | perl -pe 'chop; /\000/ ? do {chop; $_ .= "\\000\n"} : do {$_ .= "\\n\n"}'
第 1 行告诉 shell 这是一个 Bash 脚本。
第 2-4 行形成命令管道。
第 2 行调用 grep(1):
选项“-P”指定该模式应解释为 Perl 兼容的正则表达式。
选项“-a”指定二进制输入应作为文本处理。
选项“-b”与“-o”组合指定应在每行输出之前打印匹配部分的字节偏移量。
选项“-o”指定只打印匹配的部分。
参数“#\d{10}($|\000)”是一个正则表达式模式——一个数字符号,后跟十个十进制数字,最后是行尾或 NUL。在 Unix/Linux 上,正则表达式行尾“$”元字符与 ASCII 回车符匹配(问题语句“\0xA”)。当在具有不同换行符编码的平台上运行时,正则表达式可能无法找到 ASCII 回车符(例如 MS-DOS 上的 CR-LF,经典 Mac OS 上的 LF 等)。
第 3 行是 Perl 单行过滤器,仅通过数字部分在所需范围内的行。
第 4 行是 Perl 单行代码,使终止换行符或 NUL 可见。
这是一个示例运行:
52:#1647787407\n
70:#1644931194\n
84:#1651134631\000
154:#1646920743\n