줄이 긴 매우 큰 파일에서 문자열을 검색하는 방법은 무엇입니까?

줄이 긴 매우 큰 파일에서 문자열을 검색하는 방법은 무엇입니까?

grep어제 실수로 잘못된 것을 사용한 것으로 밝혀졌습니다 . 방금 bash 기록을 확인하고 내가 무엇을 하고 있는지 확인했습니다.

grep search-string-here -f large-file-with-long-lines.txt

이것이 메모리 고갈의 원인입니다.

구현하다:

grep search-string-here large-file-with-long-lines.txt

...원하는 동작이 있습니다.

비슷한 오류가 있는 문제를 지적해 주신 @αГsнιι님께 감사드리며, 줄 길이와 메모리 grep사용 방식에 대한 가정을 수정해 주신 @EdMorton 및 @ilkkachu에게 감사드립니다.awk

아래는 원래 질문(8GB RAM을 수용할 수 없는 긴 와이어에 대해 틀렸지만)과 @EdMorton이 수락한 답변입니다.

문자열을 검색하려는 매우 긴 줄(8GB RAM에도 맞지 않음)이 있는 매우 큰 파일(100GB 이상)이 있습니다. 전체 행을 메모리에 맞추려고 하기 grep때문에 이 작업을 수행할 수 없다는 것을 알고 있습니다 .grep

지금까지 내가 생각해낸 최고의 솔루션은 다음과 같습니다.

awk '/search-string-here/{print "Found."}' large-file-with-long-lines.txt

저는 실제로 이 솔루션에 만족하지만 이 작업을 수행하는 좀 더 직관적인 방법이 있는지 궁금합니다. 어쩌면 다른 구현이 있을까요 grep?

답변1

이는 검색하려는 문자열(또는 정규식)에 나타나지 않는 문자가 있는 경우에만 작동하는 간단한 부분 솔루션이지만온라인에 자주 등장해당 문자 발생 사이의 공간이 항상 메모리에 맞도록 합니다. 예를 들어 각 행이 비교적 짧은 세미콜론으로 구분된 필드로 구성된 매우 긴 목록이라고 가정합니다.

<large-file-with-long-lines.txt tr ';' '\n' | grep 'search-string-here'

이는 다른 부분 솔루션입니다.발생 횟수는 항상 줄 시작 부분 이후 N 문자의 배수에서 시작됩니다., 일부 고정된 N의 경우 그것은 사용한다fold개행 및ag여러 줄 검색을 수행합니다. 이 예에서는 해당 항목이 항상 줄 시작 부분 뒤에서 3*x 문자로 시작되는 것으로 알려져 있습니다.

<large-file-with-long-lines.txt fold -w3 | ag $'cat\ntag\ngag\nact'

이는 각 오프셋을 반복적으로 검색하여 임의의 문자열 검색으로 일반화할 수 있습니다.

<large-file-with-long-lines.txt fold -w3 | ag $'fee\n-fi\n-fo\n-fu\nm|fe\ne-f\ni-f\no-f\num|f\nee-\nfi-\nfo-\nfum'

문자열이 거의 존재하지만 중간에 줄 바꿈이 있는 경우 거짓 긍정이 발생할 수 있습니다.

답변2

입력 파일을 여러 번 읽기 때문에 속도가 느려지지만(찾으려는 문자열의 각 문자에 대해 한 번, 검색 문자열의 크기를 문자열에서 읽을 때마다) 작동해야 합니다. 여러 문자 RS합계 에 GNU awk를 사용하여 모든 크기 RT(테스트되지 않음):

awk -v str='search-string-here' '
    BEGIN {
        lgth = length(str)
        RS = sprintf("%*s",lgth,"")
        gsub(/ /,".",RS)
        for (i=1; i<lgth; i++) {
            ARGV[ARGC++] = ARGV[1]
        }
    }
    RT == str {
        print "found"
        exit
    }
' file

RS를 N s로 설정합니다 .(여기서 N은 검색 문자열의 길이). 입력에서 문자 #1로 시작하는 모든 N 문자 체인을 읽고 이를 검색 문자열과 비교합니다. 입력의 현재 N 문자가 문자인 경우 검색과 일치하면 문자열이 종료됩니다. 해당 패스와 일치하는 항목이 없으면 동일한 작업을 다시 수행하지만 char #2부터 시작하여 N 번 완료될 때까지 계속되므로 비교할 입력 파일에 길이가 N인 문자열이 더 이상 없습니다. 검색 문자열로 .

위의 내용은 정규식 비교가 아닌 문자열 비교를 수행하고 있다는 점에 유의하세요. 정규식 비교를 수행하려면 다른 방법으로 일치하는 문자열의 최대 길이를 결정한 다음 정규식 비교 연산자를 ~대신 사용해야 합니다 ==. 예를 들어 입력에서 일치하는 문자열이 20자를 초과할 수 없다는 것을 알고 있는 경우 그러면 당신은 이렇게 할 수 있습니다:

awk -v regexp='search-regexp-here' '
    BEGIN {
        lgth = 20
        RS = sprintf("%*s",lgth,"")
        gsub(/ /,".",RS)
        for (i=1; i<lgth; i++) {
            ARGV[ARGC++] = ARGV[1]
        }
    }
    RT ~ regexp {
        print "found"
        exit
    }
' file

그러나 정규식 검색에는 문자열 검색에서 고려할 필요가 없는 몇 가지 결함이 있습니다. 예를 들어 검색 정규식이 경계로 ^또는 $를 포함하는 경우 읽을 때 각 문자 문자열 시작/끝 경계 주위에 문자를 생성하므로 위의 잘못된 일치를 얻을 수 있습니다. N자 길이의 문자열.

관련 정보