首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >查找块设备上的regex事件(行长缓冲区问题)

查找块设备上的regex事件(行长缓冲区问题)
EN

Unix & Linux用户
提问于 2022-06-19 13:30:20
回答 2查看 173关注 0票数 3

我试图在两个以#字符开头、介于1635700000到1653699999之间、以空字符(\0)或linux (\0xA)结尾的块设备上查找所有数字。

我想出了一个绝对不优雅的grep

代码语言:javascript
复制
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

即使不能像这样输入和执行它,这里还是有一些换行符的相同语句,以提高它的可读性。

代码语言:javascript
复制
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

这在其中一个块设备上有效,但是在另一个块设备上,在一些但不是所有的输出之后,它停止了错误:

代码语言:javascript
复制
grep: exceeded PCRE's line length limit

我猜失败的块设备有更长的字节段,没有\0\0xA字符,超过了行长限制阈值。

因此,我尝试将空字符更改为换行符:

代码语言:javascript
复制
sed 's/\x0/\n/g' /dev/device | grep ...

但是,它停止的原因大致相同:

代码语言:javascript
复制
sed: regex input buffer length larger than INT_MAX

我怎样才能在第二个街区设备上找到我想要找到的东西呢?非常肯定,它需要一个不同的实用程序,要么使用更大的输入缓冲区,要么不读取整行,甚至可能是定制的perl/python/C/C++程序。

我确实需要每个匹配的输出为一行,包括字节偏移量和找到的数字。

修改块设备不是一个选项。将会有成千上万的结果,所以手工搜索类似于十六进制编辑器也不是一种选择。

EN

回答 2

Unix & Linux用户

发布于 2022-06-20 20:55:44

在上面的评论中,@terdon首先给出了减少搜索空间的关键见解。通过使用扩展的grep模式语法来减少给perl (PCRE) grep模式语法的最大行长度,我能够让它工作起来。

代码语言:javascript
复制
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

即使不能像这样输入和执行它,这里还是有一些换行符的相同语句,以提高它的可读性。

代码语言:javascript
复制
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
EN

Unix & Linux用户

发布于 2022-07-21 05:07:06

下面是一个使用bash(1)、grep(1)和perl(1)的解决方案:

代码语言:javascript
复制
 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上运行CR,在经典Mac上运行LF等等)。

第3行是一个Perl单行过滤器,它只传递数值部分在所需范围内的行。

第4行是一个Perl一行程序,它使终止的换行符或NUL可见。

下面是一个示例运行:

代码语言:javascript
复制
52:#1647787407\n
70:#1644931194\n
84:#1651134631\000
154:#1646920743\n
票数 0
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/706741

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档