![sed 스크립트는 마지막 패턴 발생과 빈 줄 사이에 줄을 인쇄합니다.](https://linux55.com/image/190435/sed%20%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94%20%EB%A7%88%EC%A7%80%EB%A7%89%20%ED%8C%A8%ED%84%B4%20%EB%B0%9C%EC%83%9D%EA%B3%BC%20%EB%B9%88%20%EC%A4%84%20%EC%82%AC%EC%9D%B4%EC%97%90%20%EC%A4%84%EC%9D%84%20%EC%9D%B8%EC%87%84%ED%95%A9%EB%8B%88%EB%8B%A4..png)
sed를 사용하여 마지막 패턴 발생과 빈 줄 사이의 텍스트를 인쇄하고 싶습니다. 예를 들어, 다음 파일에서:
$ cat file
pattern
1
2
3
pattern
4
5
pattern
6
7
8
9
10
11
그냥 인쇄하고 싶어요
6
7
8
9
나는 sed '/pattern/{:1;$!{/^$/!{N;b1};h}};${x;p};d' file
부터 시도한다여기, 하지만 작동하지 않습니다.
편집: 이것은 거의 작동합니다:
$ sed -n -e '/pattern/ {n; :a; $!{/\n$/!{N;ba};h} }; $ { x;p }' file
6
7
8
9
마지막에 빈 줄을 제거하는 방법은 무엇입니까?
Edit2: 이것은 작동하는 솔루션입니다.
$sed '/pattern/{:1;$!{/\n$/!{N;b1};h}};${x;s/pattern\n//;s/\n$//;p};d' file
6
7
8
9
Edit3: 이것이 더 좋습니다:
$sed '/pattern/{:1;$!{/\n$/!{N;b1};s///;h}};${x;s/pattern\n//;p};d' file
답변1
스트림 편집기를 사용하여 sed
패턴 레코드를 감지하고 거기에서 줄을 건너뛰고 다음 빈 줄을 찾을 때까지 반복합니다. 그때까지는 패턴 공간의 레코드가 누적되며, 루프 이후에는 홀드 공간의 내용을 패턴 공간의 내용으로 덮어씁니다. 이것은 모든 패턴...빈 라인 블록에 대해 다시 발생합니다. 파일 끝에서 보류 내용을 검색하고 비어 있지 않으면 인쇄합니다.
$ sed -ne '
/pattern/{
$d;n
:loop
s/\n$//;tdone
$bdone;N
bloop
:done
x
}
${x;/./p;}
' file
6
7
8
9
최대. 라인 편집기는 이 범위와 같은 문제에 자연스럽게 적합합니다.편집하다
ed -s file <<\eof
a
.
?pattern?+1;/^$/-1p
Q
eof
GNU sed 편집기를 사용하는 또 다른 방법은 범위 연산자를 사용하여 예약된 공간의 블록을 수집하는 것입니다.
sed -e '
/pattern/,/^$/!ba
/./!ba
H;/pattern/{z;x;}
:a
$!d;x;s/.//
' file
우리는 Slurp 모드에서 GNU sed 편집기를 사용할 수 있고 패턴의 마지막 인스턴스에 도달하기 위해 정규 표현식의 욕심 많은 특성을 사용할 수 있습니다.
sed -Ez '
s/.*pattern\n(([^\n]+\n)+)(\n.*)?/\1/
' file
다음은 Perl의 범위 연산자에 해당하는 sed입니다. Array@A는 블록 라인의 집수 구역 역할을 합니다.
perl -ne 'next unless
my $e = /pattern/ .. /^$/;
@A = $e == 1 ? ()
: /./ ? (@A, $_)
: @A;
}{print @A;
' file
답변2
awk '/pattern/,/^$/ { arr[NR]=$0; if (/pattern/) line1=NR; if (/^$/) line2=NR}END{ if (line1) for(i=++line1;i<line2;i++) print arr[i]}' file
/pattern/,/^$/
패턴과 빈 줄 사이에 선이 생깁니다.
그런 다음 if (/pattern/) line1=NR
패턴이 발견된 마지막 행의 레코드 번호를 제공합니다. if (/^$/) line2=NR
마지막 빈 줄의 줄 번호를 제공합니다패턴을 찾은 후.
마지막으로 두 레코드 사이의 for 루프는 예상된 출력을 반환합니다.
패턴과 다음 빈 줄 사이에 두 줄이 없거나, 패턴이 파일에 없거나, 패턴 외부에 빈 줄이 없으면 이 작업은 실패합니다. (에서 가져옴여기)
답변3
내 생각에는,이전 솔루션이 문제를 해결하기 위해 확장할 수도 있습니다.
printf '%s\n' '?pattern?+1' '. +1,/^$/ -1 p' | ed -s file
그러면 다음 주소로 두 가지 명령이 전송됩니다 ed
.
?pattern?+1
-- 파일 끝에서 뒤로 패턴을 검색한 다음 일치하는 항목에서 한 줄 앞으로 이동하면 해당 줄이 인쇄됩니다.. +1,/^$/ -1 p
-- 다음 줄(현재 줄 + 1)부터 다음 빈 줄( ) 이전 줄까지/^$/ -1
인쇄합니다 .
pattern
해당 작업 과 다음 빈 줄 사이에 두 줄이 없거나, pattern
파일에 없거나, 그 뒤에 빈 줄이 없으면 pattern
이 작업은 실패합니다 .
답변4
이것은 아마도 가장 간단할 것입니다 awk
:
$ awk -v RS='' -F '\n' '$1 ~ /pattern/ { hold = $0 } END { if (hold != "") print hold }' file | sed 1d
6
7
8
9
awk
RS
이는 "단락 읽기 모드" 로 들어가는 빈 입력 레코드 구분 기호와 함께 사용됩니다. awk
즉, 한 번에 전체 단락을 가져옵니다 $0
. 또한 이는 단락의 첫 번째 줄과 마찬가지로 -F '\n'
단락의 각 줄이 별도의 필드가 된다는 의미로 도 사용됩니다 .$1
이 코드는 정규식이 pattern
단락의 첫 번째 줄과 일치하는지 테스트합니다. 그렇다면 변수에 단락이 유지됩니다 hold
.
마지막으로 hold
비어 있지 않으면 인쇄하십시오.
sed
출력의 첫 번째 라인(일치하는 라인 pattern
)을 삭제하는 데 사용됩니다.
$pattern
정적 모드 대신 쉘 변수를 사용하려면 다음을 수행하십시오 .
pattern=$pattern awk -v RS='' -F '\n' '$1 ~ ENVIRON["pattern"] { hold = $0 } END { if (hold != "") print hold }' file | sed 1d