매우 간단한 검색을 수행했습니다.
grep -R Milledgeville ~/Documents
그리고 잠시 후이 오류가 나타납니다.
grep: memory exhausted
어떻게 피할 수 있습니까?
시스템에 10GB의 RAM이 있고 응용 프로그램이 거의 없습니다. 실행 중이므로 간단한 grep이 메모리가 부족하다는 사실에 정말 놀랐습니다. ~/Documents
는 약 100GB이며 모든 종류의 파일을 포함합니다.
grep -RI
에는이 문제가 없을 수도 있지만 원합니다. 바이너리 파일에서도 검색 할 수 있습니다.
답변
두 가지 잠재적 인 문제 :
-
grep -R
(OS / X 10.8 이상에있는 수정 된 GNUgrep
제외)는 심볼릭 링크를 따릅니다.~/Documents
에 100GB의 파일이 있습니다. 예를 들어/
에 대한 심볼릭 링크가 여전히있을 수 있으며 다음을 포함한 전체 파일 시스템을 검색하게됩니다./dev/zero
와 같은 파일. 최신 GNUgrep
와 함께grep -r
를 사용하거나 표준 구문을 사용합니다.find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(단, 종료 상태는 패턴이 일치하는지 여부를 반영하지 않습니다.)
-
grep
는 패턴과 일치하는 줄을 찾습니다.이를 위해 메모리에 한 번에 한 줄씩로드해야합니다. 다른 많은 iv id = “cc67858b36″과 달리 GNUgrep
>
구현은 읽는 행의 크기에 제한이 없으며 바이너리 파일에서 검색을 지원합니다. 따라서 사용 가능한 메모리보다 큰 줄이 매우 큰 (즉, 두 개의 줄 바꿈 문자가 매우 멀리있는) 파일이 있으면 실패합니다.
이것은 일반적으로 a에서 발생합니다. 희소 파일입니다. 다음과 같이 재현 할 수 있습니다.
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 {} +
입력을 . 문제가 스파 스 파일로 인한 경우에 적용됩니다.
대용량 파일에 대해서만 수행하여 최적화 할 수 있습니다.
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 {} + \)
파일이 스파 스가 아니고 iv id =”14dfe9e720 “이전의 GNU 버전 grep
이있는 경우 >
, --mmap
옵션을 사용할 수 있습니다. 라인이 복사되는 것과 반대로 메모리에 mmapped되므로 시스템이 항상 메모리를 회수 할 수 있습니다. y 페이지를 파일로 페이징합니다. 이 옵션은 GNU grep
2.6
댓글
Answer
저는 보통
find ~/Documents | xargs grep -ne "expression"
여러 가지 방법을 시도해 보았는데 이것이 가장 빠른 것으로 나타났습니다. 이것은 파일 이름에 공백이있는 파일을 잘 처리하지 못합니다.이 경우를 알고 있고 grep의 GNU 버전이있는 경우 다음을 사용할 수 있습니다.
find ~/Documents -print0 | xargs -0 grep -ne "expression"
사용할 수없는 경우 :
find ~/Documents -exec grep -ne "expression" "{}" \;
모든 파일에 대해 grep을 exec
사용할 수 있습니다.
댓글
- 공백이있는 파일에서 중단됩니다.
- 음, 맞습니다.
-
find -print0 | xargs -0 grep -ne 'expression'
- @ChrisDown을 사용하면 고장난 휴대용 솔루션이 아니라 비확산적인 솔루션입니다.
- @ChrisDown Most 주요 유니스는 지금까지
find -print0
및xargs -0
를 채택했습니다 : 세 가지 BSD, MINIX 3, Solaris 11,…
답변
이 문제를 해결할 수있는 몇 가지 방법을 생각할 수 있습니다.
-
대신 한 번에 모든 파일을 검색하려면 한 번에 하나의 파일을 수행하십시오.예 :
find /Documents -type f -exec grep -H Milledgeville "{}" \;
-
단어가 포함 된 파일 만 알고 싶다면
grep -l
대신. grep은 첫 번째 히트 이후 검색을 중단하므로 “대용량 파일을 계속 읽을 필요가 없습니다. -
실제 텍스트도 원한다면 문자열 2 개를 사용할 수 있습니다. 별도의 그립 :
for file in $( grep -Rl Milledgeville /Documents ); do grep -H Milledgeville "$file"; done
댓글
- 마지막 예 유효한 구문이 아닙니다. ' 명령 대체를 수행해야합니다 ('이를 수행해서는 안됩니다.
grep
는 파일 이름에 유효한 구분 기호를 사용하여 출력합니다. 또한$file
를 인용해야합니다. - 후자의 예는 문제가 있습니다. 파일 이름에 줄 바꿈이나 공백이있는 문제가있는 경우 (
for
가 파일을 두 개의 인수로 처리하게됩니다.) - @DravSloan 편집, 개선, 여전히 법적 파일 이름에 문제가 있습니다.
- 네 답변의 일부 였기 때문에 그대로 두었습니다. 실행되도록 개선하려고했습니다. s 파일에 공백 / 줄 바꿈 등이 없음).
- 그의 수정-> 그녀, 사과드립니다 Jenny : /
답변
손실 된 데이터를 검색하기 위해 6TB 디스크를 찾고 있는데 메모리 소모 오류가 발생했습니다. 이것은 다른 파일에서도 작동합니다.
우리가 생각 해낸 해결책은 dd를 사용하여 디스크를 청크 단위로 읽고 청크를 그레 핑하는 것입니다. 다음은 코드 (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
댓글
- 읽지 않은 경우 청크가 겹치면 청크 경계에서 일치를 놓칠 수 있습니다. 겹치는 부분은 최소한 일치 할 것으로 예상되는 문자열만큼 커야합니다.
- 각 100MB 청크에서 추가로 1MB를 검색하도록 업데이트되었습니다. 저렴한 해킹
grep
는 지금까지 처리 한 버퍼를 삭제할 수 있습니다. 몇 킬로바이트 이상의 메모리를 사용하지 않고도grep
yes
의 출력을 무기한으로 사용할 수 있습니다. 문제는 라인의 크기 입니다.--null-data
옵션도 여기에서 유용 할 수 있습니다. 줄 바꿈 대신 NUL을 입력 줄 종결 자로 강제 사용합니다.dd if=/dev/sda | fold -b $((4096*1024*1024)) | grep -a "some string"
를 생각해보세요.