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자 길이의 문자열.