递归搜索十六进制序列的二进制文件目录?

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

鉴于以下目标,是否有可能改进这一点:

我不太确定 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>

命令 almostBSD 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 总是做后者);此外,只在此处报告匹配本身是有益的,因为尝试打印 整行 会导致不可预测的长输出行,因为二进制文件中没有行的概念;然而,无论哪种方式,从二进制文件输出字节都可能导致终端出现奇怪的呈现行为。