패턴 공간과 홀드 공간을 사용한 sed 성능

패턴 공간과 홀드 공간을 사용한 sed 성능

425M 텍스트 파일이 주어지면 내용은 다음과 같습니다.

--START--
Data=asdfasdf
Device=B
Lorem=Ipsum
--END--
--START--
Data=asdfasdf
Lorem=Ipsum
Device=A
--END--
--START--
Device=B
Data=asdfasdf
--END--
...

작업은 과 (및 포함) 사이의 모든 내용을 sed인쇄하는 것입니다 . 두 가지 솔루션이 제공됩니다--START----END--Device=A여기그리고여기. 두 명령 간에는 실행 시간 차이가 큽니다. 두 번째 명령은 매우 빠르지만 작동 방식에 대해 더 많은 설명이 필요합니까?

$ sed -n '/--START--/{:a;N;/--END--/!ba; /Device=A/p}' file
$ sed 'H;/--START--/h;/--END--/!d;x;/Device=A/!d' file

첫 번째 명령에 대한 설명:

작동 방식:

/--START--/{...}포함된 행에 도달할 때마다 --START--중괄호 안의 명령이 실행됩니다 {...}.

:a;레이블 "a"를 정의합니다.

N;다음 줄을 읽고 패턴 공간에 추가하세요.

/--END--/!ba패턴 공간에 현재 레이블이 포함되어 있지 않으면 --END--레이블로 다시 이동합니다 a.

/Device=A/p여기까지 오면 패턴 공간이 로 시작 --START--하고 으로 끝난다는 뜻입니다 --END--. 추가적으로, 패턴 공간에 그것이 포함되어 있다면 Device=A, 그것을 인쇄( p)하세요.

두 번째 명령 설명:

sed 'H              #add line to hold space
     /--START--/h   #put START into hold space (substitute holded in)
     /--END--/!d    #clean pattern space (start next line) if not END
     x              #put hold space into pattern space
     /Device=A/!d   #clean pattern space if it have not "Device=A"
    ' file

답변1

명심해야 할 한 가지는 정규식 일치가 "비용이 많이 든다"는 것입니다. 따라서 패턴 버퍼에 항목이 많을수록 검색 속도가 느려집니다.
이 특별한 경우에는 sed세 가지 패턴을 찾아야 합니다(1, 2, 3으로 번호를 매기겠습니다): 범위 START(1), 범위 END(2) 및 해당 범위 내 MATCH(3)(있는 경우).

두 솔루션의 주요 차이점은 범위의 모든 라인을 저장하는 데 사용되는 버퍼이며, 이는 범위의 끝을 감지하는 방법을 결정합니다.

첫 번째 솔루션은 각 줄에서 START(1)를 검색하는 방식으로 작동하며, 이를 찾으면 패턴 공간에 줄을 추가하기 시작하고 각 반복마다 END(2)의 범위를 확인해야 합니다(매번 새로운 데이터 행을 추가합니다). 한 번에 패턴 공간에서전체 버퍼를 다시 검색합니다.END를 입력하면 언제 멈춰야 할지 알 수 있습니다.) 일단 찾으면,전체 패턴 공간에서 MATCH(3)을 검색합니다..

두 번째 솔루션은 다르게 작동합니다. 즉, 예약된 공간에 행을 무조건 누적하여 H행당 두 가지 패턴 일치(START(1) 및 END(2))를 수행하여 각각 범위를 결정합니다. 이것은매우 빠르다. 범위의 끝을 감지하면 x버퍼를 변경합니다(이제 패턴 공간에는 예약된 공간에 누적된 모든 행이 포함됩니다).MATCH(3)에 대한 전체 패턴 공간 검색.

보시다시피 (3)은정확히 똑같다두 경우 모두: 두 sed스크립트 모두 MATCH 검색을 실행합니다.패턴 공간에 START부터 END까지 모든 라인이 포함되면. 따라서 두 솔루션을 구별하는 것은 MATCH 검색이 아닙니다. 여기서 주요 차이점은 (2)에 의해 발생합니다.
두 번째 솔루션은 각 라인에서 END를 검색합니다. 라인에 END가 포함되어 있지 않으면 d패턴 공간에서 이를 제거하고 루프를 다시 시작합니다. 즉, 다른 라인을 가져온 다음 다시 , END 등을 찾으려고 합니다. END가 발견되기 전에는 패턴 공간에 한 줄 이상이 없습니다.
대조적으로, 첫 번째 솔루션은 a;N;/--END--/!ba 이전 실행과의 차이점이 단 한 줄로 구성되어 있어도 점점 더 큰 텍스트 버퍼에서 계속해서 실행됩니다. 대용량 텍스트 파일을 작업할 때 이는 결코 좋은 일이 아닙니다. START-END 범위가 수천 줄에 걸쳐 있다고 상상해 보십시오...

즉, 검색 범위가 종료되면 작업 속도가 느려집니다.


첫 번째 기술이 두 번째 기술과 비교하여 얼마나 느린지에 대한 좋은 예는 여기에서 찾을 수 있습니다.

목록을 구분 기호를 사용하여 한 줄로 변환

내 테스트에서 볼 수 있듯이 첫 번째 솔루션은 테스트를 완료하지도 못했습니다.

관련 정보