递归搜索十六进制序列的二进制文件目录?
Recursively search directory of binary files for hexadecimal sequence?
我用来搜索一些十六进制值(比如 0A 8b 02
)的当前命令包括:
find . -type f -not -name "*.png" -exec xxd -p {} \; | grep "0a8b02" || xargs -0 -P 4
鉴于以下目标,是否有可能改进这一点:
- 递归搜索文件
- 显示偏移量和文件名
- 排除某些具有某些扩展名的文件(以上示例不会搜索
.png
个文件)
- 速度:搜索需要直接处理 200,000 个文件(大约 50KB 到 1MB),总共约 2GB。
我不太确定 xargs
是否能在 4 个处理器上正常工作。此外,当 grep
找到匹配项时,我在打印文件名时遇到了困难,因为它是从 xxd
通过管道传输的。有什么建议吗?
如果:
- 你有 GNU
grep
- 并且您搜索的十六进制字节从不包含换行符 (
0xa
)[1]
- 如果它们包含 NUL (
0x
),您必须通过文件 (-f
) 而不是直接参数提供 grep
搜索字符串。
以下命令将带您到达那里,使用搜索 0e 8b 02
:
的示例
LC_ALL=C find . -type f -not -name "*.png" -exec grep -FHoab $'\x{0e}\x{8b}\x{02}' {} + |
LC_ALL=C cut -d: -f1-2
grep
命令产生如下输出行:
<filename>:<byte-offset>:<matched-bytes>
然后 LC_ALL=C cut -d: -f1-2
减少到 <filename>:<byte-offset>
命令 almost 与 BSD grep
一起工作,除了报告的字节偏移总是 [=69=匹配模式的行的 ]start。
换句话说:只有在文件中匹配项之前没有换行符时字节偏移才是正确的。
此外,BSD grep
不支持将 NUL (0x0
) 字节指定为搜索字符串的一部分,即使通过带有 -f
.
的文件提供也不支持
- 请注意,没有个并行处理,但只有几个
grep
个调用,基于使用find
的 -exec ... +
,它与 xargs
一样,一次将命令行中适合的文件名传递给 grep
。
- 让
grep
直接搜索字节序列,不需要xxd
:
- 序列被指定为ANSI C-quoted string,这意味着转义序列被shell扩展为文字,使Grep能够随后搜索对于结果字符串 作为文字 (通过
-F
),速度更快。
链接的文章来自 bash
手册,但它们也适用于 zsh
(和 ksh
)。
- GNU Grep 替代方案是使用
-P
(支持 PRCE,Perl 兼容的正则表达式)和非预扩展的转义序列,但这会 更慢 : grep -PHoab '\x{0e}\x{8b}\x{02}'
LC_ALL=C
确保 grep
将每个 字节 视为自己的字符,而不应用任何编码规则。
-F
将搜索字符串视为文字(而不是正则表达式)
-H
将相关的输入文件名添加到每个输出行;请注意,当给定超过 1 个文件名参数时,Grep 会隐式执行此操作
-o
只报告匹配的字符串(字节序列),而不是整行(行的概念无论如何在二进制文件中没有意义)[2]
-a
将二进制文件视为文本文件(如果没有这个,Grep 只会为具有匹配项的二进制输入文件打印文本 Binary file <filename> matches
)
-b
报告匹配项的字节偏移量
如果在给定的输入文件中最多可以找到 1 个匹配项,则添加 -m 1
.
[1] 不能使用换行符,因为 Grep 总是将搜索模式字符串中的换行符视为分隔 多个 搜索模式。另外,Grep 是基于 line 的,所以你不能跨行匹配; GNU Grep 的 -null-data
将输入拆分为 NUL 字节的选项可能会有所帮助,但前提是您的搜索字节序列不包含 NUL 字节;您还必须在 regex 中将字节值表示为 escape sequences 并结合 -P
- 因为您需要使用转义序列 \n
代替实际的换行符。
[2] -o
需要 -b
报告 匹配 的字节偏移量行首(如前所述,不幸的是,BSD Grep 总是做后者);此外,只在此处报告匹配本身是有益的,因为尝试打印 整行 会导致不可预测的长输出行,因为二进制文件中没有行的概念;然而,无论哪种方式,从二进制文件输出字节都可能导致终端出现奇怪的呈现行为。
我用来搜索一些十六进制值(比如 0A 8b 02
)的当前命令包括:
find . -type f -not -name "*.png" -exec xxd -p {} \; | grep "0a8b02" || xargs -0 -P 4
鉴于以下目标,是否有可能改进这一点:
- 递归搜索文件
- 显示偏移量和文件名
- 排除某些具有某些扩展名的文件(以上示例不会搜索
.png
个文件) - 速度:搜索需要直接处理 200,000 个文件(大约 50KB 到 1MB),总共约 2GB。
我不太确定 xargs
是否能在 4 个处理器上正常工作。此外,当 grep
找到匹配项时,我在打印文件名时遇到了困难,因为它是从 xxd
通过管道传输的。有什么建议吗?
如果:
- 你有 GNU
grep
- 并且您搜索的十六进制字节从不包含换行符 (
0xa
)[1]- 如果它们包含 NUL (
0x
),您必须通过文件 (-f
) 而不是直接参数提供grep
搜索字符串。
- 如果它们包含 NUL (
以下命令将带您到达那里,使用搜索 0e 8b 02
:
LC_ALL=C find . -type f -not -name "*.png" -exec grep -FHoab $'\x{0e}\x{8b}\x{02}' {} + |
LC_ALL=C cut -d: -f1-2
grep
命令产生如下输出行:
<filename>:<byte-offset>:<matched-bytes>
然后 LC_ALL=C cut -d: -f1-2
减少到 <filename>:<byte-offset>
命令 almost 与 BSD grep
一起工作,除了报告的字节偏移总是 [=69=匹配模式的行的 ]start。
换句话说:只有在文件中匹配项之前没有换行符时字节偏移才是正确的。
此外,BSD grep
不支持将 NUL (0x0
) 字节指定为搜索字符串的一部分,即使通过带有 -f
.
- 请注意,没有个并行处理,但只有几个
grep
个调用,基于使用find
的-exec ... +
,它与xargs
一样,一次将命令行中适合的文件名传递给grep
。 - 让
grep
直接搜索字节序列,不需要xxd
:- 序列被指定为ANSI C-quoted string,这意味着转义序列被shell扩展为文字,使Grep能够随后搜索对于结果字符串 作为文字 (通过
-F
),速度更快。
链接的文章来自bash
手册,但它们也适用于zsh
(和ksh
)。- GNU Grep 替代方案是使用
-P
(支持 PRCE,Perl 兼容的正则表达式)和非预扩展的转义序列,但这会 更慢 :grep -PHoab '\x{0e}\x{8b}\x{02}'
- GNU Grep 替代方案是使用
LC_ALL=C
确保grep
将每个 字节 视为自己的字符,而不应用任何编码规则。-F
将搜索字符串视为文字(而不是正则表达式)-H
将相关的输入文件名添加到每个输出行;请注意,当给定超过 1 个文件名参数时,Grep 会隐式执行此操作-o
只报告匹配的字符串(字节序列),而不是整行(行的概念无论如何在二进制文件中没有意义)[2]-a
将二进制文件视为文本文件(如果没有这个,Grep 只会为具有匹配项的二进制输入文件打印文本Binary file <filename> matches
)-b
报告匹配项的字节偏移量
- 序列被指定为ANSI C-quoted string,这意味着转义序列被shell扩展为文字,使Grep能够随后搜索对于结果字符串 作为文字 (通过
如果在给定的输入文件中最多可以找到 1 个匹配项,则添加 -m 1
.
[1] 不能使用换行符,因为 Grep 总是将搜索模式字符串中的换行符视为分隔 多个 搜索模式。另外,Grep 是基于 line 的,所以你不能跨行匹配; GNU Grep 的 -null-data
将输入拆分为 NUL 字节的选项可能会有所帮助,但前提是您的搜索字节序列不包含 NUL 字节;您还必须在 regex 中将字节值表示为 escape sequences 并结合 -P
- 因为您需要使用转义序列 \n
代替实际的换行符。
[2] -o
需要 -b
报告 匹配 的字节偏移量行首(如前所述,不幸的是,BSD Grep 总是做后者);此外,只在此处报告匹配本身是有益的,因为尝试打印 整行 会导致不可预测的长输出行,因为二进制文件中没有行的概念;然而,无论哪种方式,从二进制文件输出字节都可能导致终端出现奇怪的呈现行为。