400GB 바이너리 파일을 grep하는 가장 빠른 방법은 무엇입니까? HDD 덤프에서 txt 파일이 필요하고 그 파일의 일부 문자열을 알고 있으며 덤프에서 파일을 찾고 싶습니다.
를 사용해 보았지만 grep -a -C 10 searchstring
grep이 개행 없이 큰 데이터 덩어리를 읽으려고 하면 메모리 부족으로 인해 충돌이 발생합니다. 그리고 처음부터 검색을 시작하는 것이 아니라 파일의 특정 지점부터 검색을 시작할 것이라고 생각했습니다.
답변1
나는 이것을 이런 식으로 사용할 것입니다 strings
:
strings 400Gfile.bin | grep -C 10 searchstring
주어진 오프셋(예: 20G)에서 시작하려면,
dd if=400Gfile.bin bs=20G skip=1 | strings | grep -C 10 searchstring
답변2
bgrep
때때로 나는 이 임의의 저장소로 돌아옵니다.https://github.com/tmbinc/bgrep
Readme "설치"에 따르면:
curl -L 'https://github.com/tmbinc/bgrep/raw/master/bgrep.c' | gcc -O2 -x c -o $HOME/.local/bin/bgrep -
최소 예의 사용 예:
printf '\x01\x02abcdabcd' > myfile.bin
bgrep -B2 -A2 6263 myfile.bin
산출:
myfile.bin: 00000003
\x02abc
myfile.bin: 00000007
dabc
6263
ASCII 형식 bc
이고 두 바이트 시퀀스가 0 인덱스 위치 3과 7에서 일치하기 때문입니다 .
SSD에서 테스트한 Lnovo ThinkPad P51의 32GB 메모리에 맞지 않는 대용량 파일을 처리할 수 있는지 살펴보겠습니다.
dd count=100M if=/dev/zero of=myfile.bin
printf '\x01\x02abcdabcd' >> myfile.bin
time bgrep -B2 -A2 6263 myfile.bin
산출:
myfile.bin: c80000003
\x02abc
myfile.bin: c80000007
dabc
real 11m26.898s
user 1m32.763s
sys 9m53.756s
그래서 시간이 좀 걸렸지만 효과가 있었습니다.
다소 짜증나는 점은 일반 텍스트 문자를 직접 검색하는 기능이 지원되지 않는다는 점입니다. 16진수 문자열을 제공해야 합니다. 하지만 우리는 기반으로 할 수 있습니다https://stackoverflow.com/questions/2614764/how-to-create-a-hex-dump-of-file- Contains-only-the-hex-characters-without-spac
bgrep `printf %s bc | od -t x1 -An -v | tr -d '\n '` myfile.bin
따라서 Bash 별칭이 도움이 될 것입니다:
bgrepa() {
pat=$1
shift
bgrep `printf %s "$pat" | od -t x1 -An -v | tr -d '\n '` "$@"
}
bgrepa bc -B2 -A2 myfile.bin
정규 표현식은 지원되지 않습니다.
Ubuntu 23.04, bgrep 28029c9203d54f4fc9332d094927cd82154331f2에서 테스트되었습니다.
답변3
grep의 문제점은 메모리에 전체 라인이 필요하다는 것입니다. 줄이 너무 커서 메모리에 맞지 않으면 grep 폭탄이 발생합니다. 이 딜레마를 해결하는 유일한 방법은 grep에 작은 덩어리를 공급하는 것입니다. (이것은 실제로 grep입니다.~해야 한다어쨌든 자체적으로 수행하고 있지만 그렇지 않습니다.)
dd
시작 오프셋을 지정할 수 있도록 사용 하고, 사용 가능한 RAM보다 큰 줄에서 메모리 부족을 방지하려면 fold
또는 를 사용하세요. 예방할 것이다grep --mmap
grep --mmap
체계차단을 방지하지만 grep 자체의 차단을 방지할 수도 있고 그렇지 않을 수도 있습니다. 누군가에게 테스트를 받는 것은 좋은 일입니다. fold
이를 통해 일정한 간격으로 개행 문자를 삽입할 수 있으며, 이는 입력을 관리 가능한 덩어리로 분할하기 위한 조건을 충족합니다.
dd if=bigfile skip=xxx | fold | grep -b -a string
이는 -b
파일에서 텍스트 문자열이 어디에 있는지 아는 데 유용할 수 있는 바이트 오프셋을 제공합니다.
검색 문자열 "Hard"를 사용하고 성능을 모니터링하기 위해 별도의 창에서 vmstat를 실행하여 KVM 하이퍼바이저 중 하나의 100GB 논리 볼륨에서 이를 테스트했습니다. 논리 볼륨은 기본적으로 게스트 Linux VM이 설치된 하드 드라이브(파티션 및 파일 시스템)로 포맷됩니다. 시스템 성능에는 영향이 없습니다. 각 공연을 약 33초 만에 처리했습니다(물론 이는 하드웨어에 따라 크게 달라질 수 있습니다).
빠른 성능을 원한다고 하셨습니다. 이는 쉘 스크립트에서 유틸리티를 사용할 때 가장 빠른 성능을 제공합니다. 더 빠른 검색을 얻는 유일한 방법은 오프셋을 찾고, 지정된 블록 크기를 읽고, 블록을 패턴 일치 알고리즘에 공급한 후 다음 블록으로 이동하는 프로그램을 C로 작성하는 것입니다. 이런 유형의 "향상된 grep"이 이미 존재해야 할 것 같지만 온라인으로 검색해 보니 찾을 수 없습니다.
답변4
실제로 텍스트이지만 개행 문자가 없는 거대한 JSON 파일(300Gb - 데이터베이스 내보내기)을 grep하는 방법을 찾았습니다. 문제는 특정 필드의 바이트 오프셋을 가져오는 것입니다.
ugrep을 사용하여 "tr"을 통해 수동 "라인"을 해결하고 만듭니다. 이렇게 하면 파일이 메모리에 완전히 로드되지 않고 ugrep이 "스트리밍" 방식으로 작동하여 적중 시 결과를 인쇄하며 바이트 오프셋은 "원시"입니다. 예를 들어 json을 조각으로 자르는 데 유용합니다.
cat ./full.json | tr '{' '\n' | ugrep --fixed-strings --byte-offset --format='%f:%b:%o%~' --binary --mmap -f ./splitstrings.txt