【发布时间】:2021-01-11 21:22:49
【问题描述】:
基本上我想要一个“将二进制字符串作为模式的多行 grep”。
例如:
printf '\x00\x01\n\x02\x03' > big.bin
printf '\x01\n\x02' > small.bin
printf '\x00\n\x02' > small2.bin
那么以下应该成立:
-
small.bin包含在big.bin中 -
small2.bin不包含在big.bin中
我不想将文件转换为带有xxd 的 ASCII 十六进制表示,如图所示,例如at:https://unix.stackexchange.com/questions/217936/equivalent-command-to-grep-binary-files 因为那感觉很浪费。
理想情况下,该工具应处理无法放入内存的大文件。
请注意,以下尝试不起作用。
grep -f 匹配不应该的位置,因为它必须拆分换行符:
grep -F -f small.bin big.bin
# Correct: Binary file big.bin matches
grep -F -f small2.bin big.bin
# Wrong: Binary file big.bin matches
$(cat) 中的 Shell 替换失败,因为它是 impossible to handle null characters in Bash AFAIK,所以字符串只会在第一个 0 处被截断,我相信:
grep -F "$(cat small.bin)" big.bin
# Correct: Binary file big.bin matches
grep -F "$(cat small2.bin)" big.bin
# Wrong: Binary file big.bin matches
已在How can i check if binary file's content is found in other binary file? 提出了一个 C 问题,但是否可以使用任何广泛可用的 CLI(希望是 POSIX 或 GNU coreutils)工具?
值得注意的是,实现诸如Boyer-Moore 之类的非朴素算法并非易事。
我可以按如下方式破解一个正常工作的 Python one 班轮,但它不适用于不适合内存的文件:
grepbin() ( python -c 'import sys;sys.exit(not open(sys.argv[1]).read() in open(sys.argv[2]).read())' "$1" "$2" )
grepbin small.bin big.bin && echo 1
grepbin small2.bin big.bin && echo 2
我还可以在 GitHub 上找到以下两个工具:
-
https://github.com/tmbinc/bgrep 用 C 语言,可安装(惊人的:-)):
curl -L 'https://github.com/tmbinc/bgrep/raw/master/bgrep.c' | gcc -O2 -x c -o /usr/local/bin/bgrep - -
https://github.com/gahag/bgrep 在 Rust 中,可通过以下方式安装:
cargo install bgrep
但它们似乎不太支持从文件中获取模式,您在命令行上将输入提供为十六进制 ASCII。我可以使用:
bgrep $(xxd -p small.bin | tr -d '\n') big.bin
因为使用xxd 转换小文件并不重要,但这并不是很好。
无论如何,如果我要实现该功能,我很可能会将其用于上面的 Rust 库。
bgrep 也在:How does bgrep work?
在 Ubuntu 20.10 上测试。
【问题讨论】:
-
rep -f matches where it shouldn't because it must be splitting newlines:并且它正在解析正则表达式。grep "$(cat small.bin)"不仅零字节失败。grep需要一个正则表达式。请注意,您的is it possible with any widely available CLI正在“寻求工具推荐”的垃圾箱中。 -
@KamilCuk true,为非正则表达式添加了
-F。如果它关闭,我会在其他地方发布,通常的程序。 -
"$(cat file-with-nulls)"正在为失败做好准备,因为 NUL 不能存储在 C 字符串中,并且 bash 中的所有字符串都是 NUL 分隔的 C 字符串。就此而言,如果grep使用能够包含 NUL 文字的字符串,我会感到非常惊讶——不,很惊讶。 -
...构建一个 Python 代码版本会是一个更合理的开始,该版本执行窗口以逐步搜索文件(obvs.,需要围绕块边界进行一些特殊情况处理;但只要可以强制执行最大大小,这些似乎都不是特别棘手)。
-
grep将整个正则表达式模式加载到内存中。我认为没有一种工具可以在二进制文件中搜索二进制字节流(不是字节缓冲区......)。如果小文件适合内存并且大文件很大,您可以编写一个简单的 C 程序来读取小文件,将其大小用作块大小,从大文件中读取块,并尝试使用memmem().
标签: bash grep posix gnu-coreutils