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

Kar*_*ter 2 linux grep

我正在从一个大型二进制文件(1 TB)中提取一个十六进制模式(当前是一个数字)

xxd -p /path/to/sda.img | tr -d '\n' | grep -ob '117a0cb17ada1002'
Run Code Online (Sandbox Code Playgroud)

我想知道为什么grep最多使用 7 GB RAM 然后崩溃并显示没有更多 RAM 可用的错误消息(我有更多(16 GB + 8 GB 交换),但我收到了消息)。我的问题是

  • grep如果不需要记住任何东西,为什么要使用这么多内存(搜索结果立即打印到标准输出(没有输出,所以我假设没有搜索结果,在较小的文件上搜索结果已显示)立即地)?
  • 如果不使用grep替代(一组)命令来完成相同的任务,我怎么能防止这种内存使用?

我删除\n以获得正确的字节偏移量。我想知道文件中的位置/没有分隔符的一行没有大量计算(减去插入的换行符等)。

grep在 Ubuntu 14.10 amd64 上运行2.20-3。

Kus*_*nda 7

由于grep逐行匹配,内存不足,并且您已明确删除管道中的所有换行符:

$ xxd -p /path/to/sda.img | tr -d '\n' | grep -ob '117a0cb17ada1002'
Run Code Online (Sandbox Code Playgroud)

我假设您想要做的是在 的输出中找到特定十六进制字符串的字节偏移量xxd,并确保您找到它(如果它存在),您删除换行符(否则字符串可能跨越两行)。

以下awk脚本将跨连续行匹配模式并将匹配的第一个字符的位置打印到终端。它假设输入正好是 60 个字符宽(就像输出一样xxd -p)。

{
    if (NR > 1 && offset = match(line $0, pattern)) {
        printf("%d: %s\n", (NR - 2)*60 + offset, pattern);
    }

    line = $0;
}
Run Code Online (Sandbox Code Playgroud)

或者,或者(但等效地):

NR > 1 {
    if (offset = match(line $0, pattern)) {
        printf("%d: %s\n", (NR - 2)*60 + offset, pattern);
    }
}

{ line = $0 }
Run Code Online (Sandbox Code Playgroud)

在随机输入数据上测试它(我正在使用的搜索字符串在数据中突出显示):

$ xxd -p random.dat | 头-n 5
 b1a632f5 218b1404d9873dc20ae80e687c99c618bfc0f92db007c36c 2888
21a9 9d23914e34510b9ab8e1c2b340cf1e4a0585b788aecbbc64f01a7a52
62e1746ca1fa4ff65d575419522d52169c5d3f9eee0e204979d79634db9b
fa78320eb7b9e072adc53720785fc7b65a1ffb04cc77566686ea74 ac00fe
f3 2afc1539690d0046bc13706404d82112442d4bc447ac95df1fe96cd4bd
$ 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
Run Code Online (Sandbox Code Playgroud)

无论如何,在 1 TB 的大文件上运行它会很慢。它可以(可能)通过提供-c 256选项xxd(并相应地在awk脚本中将 60 更改为 256 )以减少模式匹配的数量来加快速度,但是每行上的数据必须至少匹配两次(一次一起与上一行,一次与下一行一起)。