我正在从一个大型二进制文件(1 TB)中greping一个十六进制模式(当前是一个数字)
xxd -p /path/to/sda.img | tr -d '\n' | grep -ob '117a0cb17ada1002'
我想知道为什么grep
使用最多 7 GB RAM,然后崩溃并显示没有更多 RAM 可用的错误消息(我有更多 RAM(16 GB + 8 GB 交换),但我收到了消息)。我的问题是
grep
如果不需要记住任何东西,为什么要使用这么多内存(搜索结果立即打印到标准输出(没有输出,所以我假设没有搜索结果,在较小的文件上搜索结果已显示)立即地)?- 如果不
grep
使用替代(一组)命令来完成相同的任务,我怎样才能防止这种内存使用?
我删除\n
以获得正确的字节偏移量。我想知道文件中的位置/没有分隔符的一行,无需进行大量计算(减去插入的换行符数量等)。
grep
我在 Ubuntu 14.10 amd64 上运行2.20-3。
答案1
grep
由于逐行匹配,您耗尽了内存,并且您已显式删除管道中的所有换行符:
$ xxd -p /path/to/sda.img | tr -d '\n' | grep -ob '117a0cb17ada1002'
我假设您想要做的是在 的输出中查找特定十六进制字符串的字节偏移量xxd
,并且为了确保找到它(如果存在),您需要删除换行符(否则该字符串可能会跨越两行)。
以下awk
脚本将匹配连续行中的模式,并将匹配的第一个字符的位置打印到终端。它假设输入正好是 60 个字符宽(就像 is 的输出一样xxd -p
)。
{
if (NR > 1 && offset = match(line $0, pattern)) {
printf("%d: %s\n", (NR - 2)*60 + offset, pattern);
}
line = $0;
}
或者,替代地(但等效地):
NR > 1 {
if (offset = match(line $0, pattern)) {
printf("%d: %s\n", (NR - 2)*60 + offset, pattern);
}
}
{ line = $0 }
在随机输入数据上测试它(我正在使用的搜索字符串在数据中突出显示):
$ xxd -p random.dat |头-n 5 b1a632f5218b1404d9873dc20ae80e687c99c618bfc0f92db007c36c2888 21a99d23914e34510b9ab8e1c2b340cf1e4a0585b788aecbbc64f01a7a52 62e1746ca1fa4ff65d575419522d52169c5d3f9eee0e204979d79634db9b fa78320eb7b9e072adc53720785fc7b65a1ffb04cc77566686ea74交流00fe f32afc1539690d0046bc13706404d82112442d4bc447ac95df1fe96cd4bd
$ xxd -p random.dat | awk -v pattern=b1a632f5 -f script.awk
1: b1a632f5
$ xxd -p random.dat | awk -v pattern=288821a9 -f script.awk
57: 288821a9
$ xxd -p random.dat | awk -v pattern=ac00fef3 -f script.awk
235: ac00fef3
无论如何,在 1 TB 大文件上运行它都会很慢。它可以(可能)通过提供-c 256
选项xxd
(并相应地将脚本中的 60 更改为 256 )来减少模式匹配的数量来加快速度awk
,但每行上的数据仍然必须匹配两次(一次一起与上一行一起,并与下一行一起一次)。