我正在做一个非常简单的搜索:
grep -R Milledgeville ~/Documents
一段时间后出现此错误:
grep: memory exhausted
如何避免这种情况?
我的系统上有10GB的RAM,运行的应用程序很少,所以我真的很惊讶一个简单的grep内存不足。~/Documents
大约100GB,其中包含各种文件。
grep -RI
可能没有这个问题,但是我也想在二进制文件中搜索。
我正在做一个非常简单的搜索:
grep -R Milledgeville ~/Documents
一段时间后出现此错误:
grep: memory exhausted
如何避免这种情况?
我的系统上有10GB的RAM,运行的应用程序很少,所以我真的很惊讶一个简单的grep内存不足。~/Documents
大约100GB,其中包含各种文件。
grep -RI
可能没有这个问题,但是我也想在二进制文件中搜索。
Answers:
两个潜在的问题:
grep -R
(grep
在OS / X 10.8及更高版本上找到经过修改的GNU除外)遵循符号链接,因此,即使其中只有100GB的文件~/Documents
,也可能会有符号链接/
,例如,您将最终扫描包括文件在内的整个文件系统喜欢/dev/zero
。使用grep -r
较新的GNU grep
,或使用标准的语法:
find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(但是请注意,退出状态不会反映该模式是否匹配的事实)。
grep
查找与模式匹配的线。为此,它必须一次在内存中加载一行。grep
与许多其他grep
实现相反,GNU 对其读取的行数没有限制,并支持在二进制文件中进行搜索。因此,如果您的文件行很大(也就是说,两个换行符相距很远),大于可用内存,它将失败。
稀疏文件通常会发生这种情况。您可以使用以下方法重现它:
truncate -s200G some-file
grep foo some-file
那一个很难解决。您可以这样做(仍然使用GNU grep
):
find ~/Documents -type f -exec sh -c 'for i do
tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0"
done' Milledgeville {} +
它将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 {} + \)
如果文件不是稀疏的,并且您在grep
之前具有GNU版本2.6
,则可以使用该--mmap
选项。这些行将被映射到内存中,而不是被复制到内存中,这意味着系统可以始终通过将页面分页到文件来回收内存。该选项已在GNU grep
2.6 中删除
grep
可以丢弃到目前为止已处理的缓冲区。您可以无限期地grep
输出,yes
而无需使用超过几千字节的内存。问题是线的大小。
--null-data
选项在这里也可能有用。它强制使用NUL代替换行符作为输入行终止符。
我通常会
find ~/Documents | xargs grep -ne 'expression'
我尝试了很多方法,发现这是最快的。请注意,这不能很好地处理文件名带有空格的文件。如果您知道这种情况,并且拥有grep的GNU版本,则可以使用:
find ~/Documents -print0 | xargs -0 grep -ne 'expression'
如果没有,您可以使用:
find ~/Documents -exec grep -ne 'expression' "{}" \;
exec
每个文件将使用grep。
find -print0 | xargs -0 grep -ne 'expression'
find -print0
和xargs -0
现在:所有三个BSD,MINIX 3,Solaris 11中,...
我可以想到一些解决方法:
而不是一次grep所有文件,一次只做一个文件。例:
find /Documents -type f -exec grep -H Milledgeville "{}" \;
如果您只需要知道哪些文件包含单词,则grep -l
改为执行。由于grep会在第一次点击后停止搜索,因此不必继续读取任何大文件
如果您确实还想要实际的文本,则可以沿以下两个字符串插入字符串:
for file in $( grep -Rl Milledgeville /Documents ); do grep -H Milledgeville "$file"; done
grep
输出使用的分隔符在文件名中是合法的)。您还需要引用$file
。
for
将文件作为两个参数来处理)
我正在抓紧6TB磁盘以搜索丢失的数据,并使内存耗尽-错误。这也应该适用于其他文件。
我们想出的解决方案是使用dd读取大块磁盘,并grepping大块。这是代码(big-grep.sh):
#problem: grep gives "memory exhausted" error on 6TB disks
#solution: read it on parts
if [ -z $2 ] || ! [ -e $1 ]; then echo "$0 file string|less -S # greps in chunks"; exit; fi
FILE="$1"
MATCH="$2"
SIZE=`ls -l $1|cut -d\ -f5`
CHUNKSIZE=$(( 1024 * 1024 * 1 ))
CHUNKS=100 # greps in (100 + 1) x 1MB = 101MB chunks
COUNT=$(( $SIZE / $CHUNKSIZE * CHUNKS ))
for I in `seq 0 $COUNT`; do
dd bs=$CHUNKSIZE skip=$(($I*$CHUNKS)) count=$(( $CHUNKS+1)) if=$FILE status=none|grep -UF -a --context 6 "$MATCH"
done