GNU grep 최적화

GNU grep 최적화

저는 grep -EPATTERN 파일에 egrep( )을 사용합니다. ( -f path/to/file).

이는 텍스트 스트림의 무한 루프에서 수행됩니다. 즉, 모든 입력을 한 번에 모아서 grep에 전달할 수는 없습니다(예: *.log).

grep이 다음 실행을 위해 PATTERN 파일에서 빌드한 NFA를 "저장"하도록 하는 방법이 있습니까?

Google을 검색하고 문서를 읽었지만 운이 없습니다.

조금 더 자세히 설명하겠습니다. IP 주소, 도메인 등과 같은 고정된 수의 문자열을 찾으려면 정규식을 사용해야 합니다(이것은 질문의 일부는 아니지만 자유롭게 다른 것을 제안할 수 있습니다). 검색은 인터넷 피드를 기반으로 이루어졌습니다. 텍스트의 흐름이라고 생각하시면 됩니다. grep스트림이기 때문에 모든 입력을 사용할 수 없습니다 . 스트림 덩어리를 축적하여 grep사용할 수 있지만( grep모든 행에 사용할 수는 없음) 그것도 제한됩니다(30초라고 가정해 보겠습니다).

grepNFA가 모든 스키마(내 경우에는 파일)에서 구축되고 있다는 것을 알고 있습니다 . 그래서 제 질문은 grep이 NFA가 변경되지 않으므로 다음 실행을 위해 저장하라고 말할 수 있습니까?입니다 . 이를 통해 매번 NFA를 구축하는 데 시간이 절약됩니다.

답변1

아니요, 그런 것은 없습니다. 일반적으로 시작 비용 grep(새 프로세스 포크, 실행 파일 로드, 공유 라이브러리, 동적 연결...)은 정규식을 컴파일하는 것보다 훨씬 높으므로 이러한 최적화는 거의 의미가 없습니다.

봤지만1250개의 문자열을 90k 패턴과 일치시키는 것이 왜 그렇게 느린가요?grep다수의 정규식을 특히 느리게 만드는 일부 GNU 버전의 버그에 관한 것입니다 .

grep여기서는 블록을 동일한 인스턴스에 제공하여 블록을 여러 번 실행하는 것을 피할 수 있습니다 grep(예: 이를 보조 프로세스로 사용하고 마커를 사용하여 끝을 감지). 다음 이외의 zshGNU grep및 구현을 사용하십시오 .awkmawk

coproc grep -E -f patterns -e '^@@MARKER@@$' --line-buffered
process_chunk() {
  { cat; echo @@MARKER@@; } >&p & awk '$0 == "@@MARKER@@"{exit};1' <&p
}
process_chunk < chunk1 > chunk1.grepped
process_chunk < chunk2 > chunk2.grepped

awkor 를 사용하여 모든 작업을 수행하는 것이 더 간단할 수도 있습니다 perl.

grep그러나 출력을 다른 청크의 다른 파일에 넣을 필요가 없다면 언제든지 다음을 수행할 수 있습니다.

{
  cat chunk1
  while wget -qO- ...; done # or whatever you use to fetch those chunks
  ...
} | grep -Ef patterns > output

답변2

스트림이기 때문에 모든 입력에 grep을 사용할 수 없습니다. 스트림의 덩어리를 모아서 수집할 수 있습니다.

배관이 막힌 것을 알고 계셨나요? grep에 무언가를 파이프하고 사용할 수 있는 입력이 없으면 grep은 사용할 수 있을 때까지 기다린 다음 입력이 항상 있었던 것처럼 계속 진행합니다.

$ ( echo a1; echo b1; sleep 5; echo a2 ) | grep 'a.'
a1
a2

편집: 파이프 작동 방식에 따라 cmd1 | cmd2두 프로그램이 동시에 시작됩니다. 예를 들어 두 프로그램 사이에 65,536바이트의 "블록 버퍼"가 있습니다. 읽기를 시도 하고 cmd2버퍼가 비어 있으면 블록을 사용할 수 있을 때까지 기다립니다. 쓰기를 시도 하고 버퍼가 가득 차면 읽을 때 cmd1까지 기다립니다 .cmd2

내가 아는 한, 입력을 덩어리로 잘라 개별적으로 grep에 전달할 필요는 없습니다. 이 작업은 자동으로 수행됩니다.

EDIT2: grep또한 스트림에서 결과가 발견되는 즉시 인쇄해야 합니다. 결과를 얻기 위해 흐름 완료가 필요하지 않습니다.

답변3

어쩌면 "모든 입력에 대해 grep"을 할 수 있을까요? nc(netcat)을 사용합니까 , 아니면 script다른 유사한 도구를 통해서입니까? 특히 패턴 파일 크기가 관리 가능한 경우(예: 정규 표현식 1000개 미만).

첫 번째 예: 몇 가지 스트림 연결을 만들 수 있습니다 egrep. (여기서 예로 사용되었지만 nc다른 것도 적용될 수 있음)

prompt:/some/path $ nc somehost someport | egrep -f patternfile | gzip -c - > results.gz

# and while this is running, you can have a look at the growing results.gz:
prompt:/some/otherpath $ tail -f /some/path/results.gz | gzip -c - | less

(참고: 명령을 touch /some/path/results.gz실행 하기 전에 아무것도 놓치지 않도록 해당 (빈) 파일을 사용할 수도 있습니다. Results.gz에는 어쨌든 캡처하려는 모든 내용이 포함됩니다.)nctail -f

두 번째 예egrep: 현재 실행 중인 셸 세션에서도 가능합니다 (그리고 진행 상황을 추적하는 다른 방법을 보여줍니다).

#in 1 terminal:
prompt:/home/userA $ script
Script command is started. The file is typescript.
prompt:/home/userA $ 
 ... doing here whatever you want (start IRC? etc) ...
prompt:/home/userA $ ctrl-d # to end the current script session
Script command is complete. The file is typescript.

#and in another terminal, while you are "doing here whatever you want" :
prompt:/home/somewhere $ tail -f /home/userA/typescript | egrep -f patternfile  | tee /some/place/to/store/results.gz

egrepgrep예, 대부분의 시스템에서 효율적인 버전입니다(흥미로운 정보 참조:https://swtch.com/~rsc/regexp/regexp1.html)

관련 정보