![sed: 마지막 패턴 발생으로 끝나는 범위가 있습니다(탐욕 범위).](https://linux55.com/image/195623/sed%3A%20%EB%A7%88%EC%A7%80%EB%A7%89%20%ED%8C%A8%ED%84%B4%20%EB%B0%9C%EC%83%9D%EC%9C%BC%EB%A1%9C%20%EB%81%9D%EB%82%98%EB%8A%94%20%EB%B2%94%EC%9C%84%EA%B0%80%20%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4(%ED%83%90%EC%9A%95%20%EB%B2%94%EC%9C%84)..png)
다음 파일을 가져옵니다.
$ 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
모든 줄을 인쇄합니다.첫 번째mno
GNU를 포함합니다 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
.abc
mno
편집하다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
인쇄되어야 함 을 나타냅니다 .f
1
- 그런 다음 각 발생 후
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
찾아 해당 라인 번호를 각각 및 에 저장합니다 .abc
mno
start
end
- 두 번째 패스에서는 카운터가 end
FNR
사이(포함)에 있을 때마다 (또는 unset보다 크거나 같은 경우 ) 줄을 인쇄합니다 .start
end
start
end
답변4
abc
예약된 공간에 있는 행부터 시작하여 모든 행을 수집 한 다음 탐욕적 속성을 사용하여 .*
마지막 행 이후의 모든 행을 삭제할 수 있습니다 mno
.
sed '/abc/,$!d;H;$!d;x;s/\n//;s/\(.*mno[^\n]*\).*/\1/'
/abc/,$!d
첫 번째 줄 앞의 모든 항목(또는 줄이 전혀 없는 경우 전체 파일 )을d
삭제 하는 것입니다 .abc
abc
H;$!d
예약된 공간에 전체 파일을 수집하는 클래식 모드입니다. (매우 큰 파일의 경우 문제가 될 수 있습니다.)- 큰 버퍼 복사를 피하기 위해
x
사용하는 대신 버퍼를 변경합니다 .g
s/\n//
빈 예약 공간에 추가하여 생성된 잘못 시작하는 개행을 제거합니다.s/\(.*mno[^\n]*\n\).*/\1/
이후 모두 삭제마지막mno
줄(또는 줄이 없으면 요청 시 나머지 파일 전체를 인쇄합니다mno
). 이는[^\n]
POSIX가 아니며 GNU와 같은 특정 버전에서만 작동합니다sed
.