如何防止 grep 过度不必要的内存使用

如何防止 grep 过度不必要的内存使用

我正在从一个大型二进制文件(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,但每行上的数据仍然必须匹配两次(一次一起与上一行一起,并与下一行一起一次)。

相关内容