저는 아주 간단한 검색을 하고 있습니다.
grep -R Milledgeville ~/Documents
얼마 후 다음과 같은 오류가 나타났습니다.
grep: memory exhausted
이것을 어떻게 피할 수 있습니까?
내 시스템에는 10GB RAM이 있고 실행 중인 응용 프로그램이 거의 없기 때문에 간단한 grep으로도 메모리가 부족할 수 있다는 사실에 정말 놀랐습니다. ~/Documents
약 100GB, 다양한 파일 포함.
grep -RI
이 문제가 없을 수도 있지만 바이너리 파일에서도 검색하고 싶습니다.
답변1
두 가지 잠재적인 문제:
grep -R
(OS/X 10.8 이상에서 발견된 수정된 GNU 제외grep
) 심볼릭 링크를 따르십시오. 따라서 100GB의 파일만 있어도~/Documents
심볼릭 링크가 남아 있을 수 있습니다/
. 예를 들어 전체 파일 시스템을 검색하게 됩니다. ./dev/zero
grep -r
최신 GNU와 함께 사용grep
하거나 표준 구문을 사용하려면:find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(그러나 종료 상태는 패턴이 일치했는지 여부를 반영하지 않는다는 점에 유의하십시오.)
grep
패턴과 일치하는 선을 찾습니다. 이렇게 하려면 메모리에 한 번에 한 행씩 로드해야 합니다.grep
다른 많은 구현과 달리 GNU는grep
읽는 줄의 크기에 제한이 없으며 이진 파일 내 검색을 지원합니다. 따라서 파일에 사용 가능한 메모리보다 큰 매우 큰 줄(예: 두 줄 바꿈)이 있으면 실패합니다.이는 일반적으로 스파스 파일에서 발생합니다. 다음 명령을 사용하여 재현할 수 있습니다.
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
. 행은 메모리에 복사되지 않고 메모리에 매핑됩니다. 즉, 시스템은 항상 파일 페이지 아웃을 통해 메모리를 회수할 수 있습니다. 이 옵션은grep
GNU 2.6에서 제거되었습니다.
답변2
나는 보통 이렇게 한다
find ~/Documents | xargs grep -ne 'expression'
여러 가지 방법을 시도해 본 결과 이 방법이 가장 빠른 것으로 나타났습니다. 이름에 공백이 있는 파일은 잘 처리되지 않습니다. 이 상황을 알고 있고 grep의 GNU 버전이 있는 경우 다음을 사용할 수 있습니다.
find ~/Documents -print0 | xargs -0 grep -ne 'expression'
그렇지 않은 경우 다음을 사용할 수 있습니다.
find ~/Documents -exec grep -ne 'expression' "{}" \;
그러면 exec
각 파일에 대해 grep 작업이 수행됩니다.
답변3
이 문제를 해결하는 여러 가지 방법을 생각해 볼 수 있습니다.
모든 파일을 한 번에 가져오는 대신 한 번에 하나의 파일만 작업하세요. 예:
find /Documents -type f -exec grep -H Milledgeville "{}" \;
어떤 파일에 이러한 단어가 포함되어 있는지 알고 싶다면
grep -l
대신 이렇게 하십시오. grep은 첫 번째 적중 이후 검색을 중지하므로 대용량 파일을 계속 읽을 필요가 없습니다.실제 텍스트도 원한다면 두 개의 개별 grep을 함께 묶을 수 있습니다.
for file in $( grep -Rl Milledgeville /Documents ); do \ grep -H Milledgeville "$file"; done
답변4
손실된 데이터를 검색하고 메모리 부족 오류가 발생하기 위해 6TB 디스크를 준비하고 있습니다. 이는 다른 파일에도 적용됩니다.
우리가 생각해낸 해결책은 dd와 grep을 사용하여 디스크 블록을 읽는 것이었습니다. 코드는 다음과 같습니다(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