Nic*_*oul 45 performance grep memory
我正在做一个非常简单的搜索:
grep -R Milledgeville ~/Documents
Run Code Online (Sandbox Code Playgroud)
一段时间后,出现此错误:
grep: memory exhausted
Run Code Online (Sandbox Code Playgroud)
我怎样才能避免这种情况?
我的系统上有 10GB 的 RAM 并且运行的应用程序很少,所以我真的很惊讶一个简单的 grep 内存不足。~/Documents大约100GB,包含各种文件。
grep -RI 可能没有这个问题,但我也想搜索二进制文件。
Sté*_*las 49
两个潜在的问题:
grep -R(除了修改的GNUgrep的OS / X 10.8及以上发现的)如下符号链接,所以即使只有100GB的文件中~/Documents,有可能仍然是一个符号链接/,例如,你最终会扫描整个文件系统,包括文件喜欢/dev/zero。使用grep -r较新的GNU grep,或使用标准的语法:
find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
Run Code Online (Sandbox Code Playgroud)
(但是请注意,退出状态不会反映模式是否匹配的事实)。
grep查找与模式匹配的行。为此,它必须在内存中一次加载一行。grep与许多其他grep实现相比,GNU对它读取的行的大小没有限制,并支持在二进制文件中搜索。因此,如果您有一个文件的行非常大(也就是说,两个换行符相距很远),并且比可用内存大,那么它就会失败。
这通常会发生在稀疏文件中。您可以使用以下方法重现它:
truncate -s200G some-file
grep foo some-file
Run Code Online (Sandbox Code Playgroud)
那个很难解决。你可以这样做(仍然使用 GNU grep):
find ~/Documents -type f -exec sh -c 'for i do
tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0"
done' Milledgeville {} +
Run Code Online (Sandbox Code Playgroud)
这会将 NUL 字符序列转换为一个换行符,然后将输入提供给grep. 这将涵盖问题由稀疏文件引起的情况。
您可以通过仅对大文件执行此操作来优化它:
find ~/Documents -type f \( -size -100M -exec \
grep -He Milledgeville {} + -o -exec sh -c 'for i do
tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0"
done' Milledgeville {} + \)
Run Code Online (Sandbox Code Playgroud)
如果文件不是稀疏的,并且您拥有grep之前的 GNU 版本2.6,则可以使用该--mmap选项。这些行将被映射到内存中而不是复制到内存中,这意味着系统始终可以通过将页面分页到文件来回收内存。该选项已在 GNU grep2.6中删除
我可以想出几种方法来解决这个问题:
不要一次 grep 所有文件,而是一次只处理一个文件。例子:
find /Documents -type f -exec grep -H Milledgeville "{}" \;
Run Code Online (Sandbox Code Playgroud)
如果您只需要知道哪些文件包含这些单词,请grep -l改为这样做。由于 grep 将在第一次命中后停止搜索,因此它不必继续读取任何大文件
如果您确实也想要实际文本,您可以将两个单独的 grep 串起来:
for file in $( grep -Rl Milledgeville /Documents ); do \
grep -H Milledgeville "$file"; done
Run Code Online (Sandbox Code Playgroud)
我通常做
find ~/Documents | xargs grep -ne 'expression'
Run Code Online (Sandbox Code Playgroud)
我尝试了很多方法,发现这是最快的。请注意,这不能很好地处理文件名带有空格的文件。如果您知道是这种情况并且拥有 GNU 版本的 grep,则可以使用:
find ~/Documents -print0 | xargs -0 grep -ne 'expression'
Run Code Online (Sandbox Code Playgroud)
如果没有,您可以使用:
find ~/Documents -exec grep -ne 'expression' "{}" \;
Run Code Online (Sandbox Code Playgroud)
这将exec是每个文件的 grep。