sed: 마지막 패턴 발생으로 끝나는 범위가 있습니다(탐욕 범위).

sed: 마지막 패턴 발생으로 끝나는 범위가 있습니다(탐욕 범위).

다음 파일을 가져옵니다.

$ cat f1
stu vwx yza
uvw xyz abc
abc def ghi
def ghi jkl
ghi jkl mno
jkl mno pqr
mno pqr stu
pqr stu vwx
stu vwx yza

첫 번째 줄부터 시작하여 다음을 포함하여 abc모든 줄을 인쇄합니다.첫 번째mnoGNU를 포함합니다 sed:

$ sed -n '/abc/,/mno/p' f1
uvw xyz abc
abc def ghi
def ghi jkl
ghi jkl mno

다음까지 모든 줄을 인쇄하려면 어떻게 해야 합니까?마지막 하나Contains mno, 예를 들어 어떻게 다음 결과를 얻을 수 있습니까?

uvw xyz abc
abc def ghi
def ghi jkl
ghi jkl mno
jkl mno pqr
mno pqr stu

즉, GNU sed의 범위 선택을 탐욕스럽게 만드는 방법이 있습니까?

고쳐 쓰다

내 설정에서는:

  • 누락된 경우 mno파일 끝까지 모든 내용을 인쇄해야 합니다.
  • mno첫 번째 이전에는 발생할 수 없습니다 abc.
  • 항상 하나 이상의 가 있으며 같은 줄에는 절대 없습니다 abc.abcmno

편집하다stu vwx yza파일이 포함된 줄로 시작하지 않도록 처음에 더미 줄을 추가했습니다. ( abc첫 번째 줄에서 시작하는 솔루션을 피하기 위해 파일은 abc포함된 첫 번째 줄에서 시작해야 합니다.)

답변1

sed '/abc/,$!d;0,/mno/b;:1;/mno/b;$d;N;b1' file

작동 알고리즘:
두 개의 주소 범위를 사용합니다.
첫 번째는 /abc/,$!d;첫 번째 패턴 일치 전에 모든 것을 제거합니다.
두 번째는 0,/mno/b;패턴이 일치할 때까지 각 라인 버퍼(패턴 공간)를 전송하여 /mno/나머지 스크립트의 출력을 우회하여 패턴이 파일에서 발견되지 않으면 삭제를 방지합니다.
나머지 스크립트는 :1;/mno/b;$d;N;b1루프에서 작동합니다. 편집기 버퍼에서는 패턴 일치가 발생할 때까지 줄이 추가됩니다. 패턴이 발견 되면 /mno/스크립트의 나머지 부분을 우회하고 전체 버퍼가 출력으로 전송됩니다. 일치하는 항목이 없으면 버퍼의 마지막 줄을 삭제합니다.

답변2

awk가능하다면 사용하시면 됩니다. 패턴이 시작되는 줄과 패턴이 멈추는 줄을 표시하고 파일의 한 패스에서 해당 줄을 인쇄할 수 있습니다( abc첫 번째 줄부터 시작하여 마지막 줄까지의 줄을 버퍼에 저장하는 작업 포함).

awk '/abc/ && !start {
  start = NR
}
/mno/ {
  stop = NR
}
start { line[NR] = $0 }
END {
  if ( !stop ) {
    stop = NR
  }
  for ( s = start; s <= stop; s++ )
    print line[s]
}' file

시작 패턴이 없으면 작동하지 않고 일련의 빈 줄만 인쇄됩니다.

답변3

awk버퍼링이 적은 또 다른 솔루션:

awk '!f&&/abc/{f=1} f==1; f==2{buf=buf $0 ORS} f&&/mno/{f=2; printf "%s",buf; buf=""}' input.txt
  • 그러면 첫 번째 항목 abc(플래그를 1로 설정 )부터 f시작하여 첫 번째 항목까지 모든 내용 이 인쇄됩니다 mno. f==1규칙 블록 외부의 명령문은 로 설정될 때마다 현재 행이 awk인쇄되어야 함 을 나타냅니다 .f1
  • 그런 다음 각 발생 후 mno( f현재 값 2) 모든 행의 내용이 버퍼에 저장되고 buf, 다음 발생 시 인쇄되고 지워집니다 mno. 처음 mno발생하는 상황 에 올바르게 대응하는지 확인하세요.앞으로먼저 이 논리를 적용하기 전에 최소 1로 설정해야 abc합니다 .f

mno따라서 두 발생 사이 또는 마지막 발생 mno과 파일 끝 사이에 최대 텍스트를 저장합니다 (단지 후자 부분은 인쇄되지 않습니다).

속도를 위해 메모리 효율성을 바꾸려는 경우 다음 2단계 접근 방식은 버퍼링에 전혀 의존하지 않습니다.

awk 'FNR==NR{if (/abc/&&!start) {start=FNR} else if (/mno/) {end=FNR}; next} FNR>=start&&(!end||FNR<=end)' input.txt input.txt

그러면 파일이 두 번 처리됩니다(따라서 매개변수로 두 번 지정).

  • 처음으로 FNR각 파일의 라인 카운터가 전역 라인 카운터와 같을 때 첫 번째 발생 과 마지막 발생을 NR찾아 해당 라인 번호를 각각 및 에 저장합니다 .abcmnostartend
  • 두 번째 패스에서는 카운터가 end FNR사이(포함)에 있을 때마다 (또는 unset보다 크거나 같은 경우 ) 줄을 인쇄합니다 .startendstartend

답변4

abc예약된 공간에 있는 행부터 시작하여 모든 행을 수집 한 다음 탐욕적 속성을 사용하여 .*마지막 행 이후의 모든 행을 삭제할 수 있습니다 mno.

sed '/abc/,$!d;H;$!d;x;s/\n//;s/\(.*mno[^\n]*\).*/\1/'
  • /abc/,$!d첫 번째 줄 앞의 모든 항목(또는 줄이 전혀 없는 경우 전체 파일 )을 d삭제 하는 것입니다 .abcabc
  • H;$!d예약된 공간에 전체 파일을 수집하는 클래식 모드입니다. (매우 큰 파일의 경우 문제가 될 수 있습니다.)
  • 큰 버퍼 복사를 피하기 위해 x사용하는 대신 버퍼를 변경합니다 .g
  • s/\n//빈 예약 공간에 추가하여 생성된 잘못 시작하는 개행을 제거합니다.
  • s/\(.*mno[^\n]*\n\).*/\1/이후 모두 삭제마지막 mno줄(또는 줄이 없으면 요청 시 나머지 파일 전체를 인쇄합니다 mno). 이는 [^\n]POSIX가 아니며 GNU와 같은 특정 버전에서만 작동합니다 sed.

관련 정보