일치하는 두 패턴 사이의 선을 찾고 있습니다. 시작 또는 끝 패턴이 누락된 경우 해당 줄은 인쇄되지 않습니다.
올바른 입력:
a
***** BEGIN *****
BASH is awesome
BASH is awesome
***** END *****
b
출력은 다음과 같습니다
***** BEGIN *****
BASH is awesome
BASH is awesome
***** END *****
이제 입력에서 END 패턴이 누락되었다고 가정합니다.
a
***** BEGIN *****
BASH is awesome
BASH is awesome
b
줄을 인쇄하면 안 됩니다.
나는 sed를 사용해 보았습니다.
sed -n '/BEGIN/,/END/p' input
END 모드가 없으면 마지막 줄까지 모든 데이터를 인쇄합니다.
어떻게 해결하나요?
답변1
다음과 같이 이 작업을 수행할 수 있습니다.
$ sed -e '
/BEGIN/,/END/!d
H;/BEGIN/h;/END/!d;g
' inp
작동 방식은 줄의 시작/끝 범위에 대해 저장 공간에 저장하는 것입니다. 그런 다음 END 줄이 나올 때까지 삭제하세요. 이때 우리는 우리가 갖고 있는 것이 무엇인지 상기하게 됩니다. OTW, 우리는 아무것도 얻지 못합니다. HTH.
답변2
cat input |
sed '/\*\*\*\*\* BEGIN \*\*\*\*\*/,/\*\*\*\*\* END *\*\*\*\*/ p;d' |
tac |
sed '/\*\*\*\*\* END \*\*\*\*\*/,/\*\*\*\*\* BEGIN *\*\*\*\*/ p;d' |
tac
두 순서 모두에서 두 개의 구분 기호를 찾을 수 tac
있도록 줄을 뒤집어 작동합니다 .sed
답변3
그리고 pcregrep
:
pcregrep -M '(?s)BEGIN.*?END'
이는 BEGIN과 END가 같은 줄에 있는 경우에도 작동하지만 다음과 같은 경우에는 작동하지 않습니다.
BEGIN 1 END foo BEGIN 2
END
pcregrep
첫 번째는 캡처되지만 두 BEGIN 1 END
번째는 캡처되지 않습니다.
이를 처리하려면 awk
다음을 수행할 수 있습니다.
awk '
!inside {
if (match($0, /^.*BEGIN/)) {
inside = 1
remembered = substr($0, 1, RLENGTH)
$0 = substr($0, RLENGTH + 1)
} else next
}
{
if (match($0, /^.*END/)) {
print remembered $0
if (substr($0, RLENGTH+1) ~ /BEGIN/)
remembered = ""
else
inside = 0
} else
remembered = remembered $0 ORS
}'
다음과 같이 입력하면:
a
BEGIN blah END BEGIN 1
2
END
b
BEGIN foo END
c
BEGIN
bar
END BEGIN
baz END
d
BEGIN
xxx
그것은 다음을 제공합니다:
BEGIN blah END BEGIN 1
2
END
BEGIN foo END
BEGIN
bar
END BEGIN
baz END
둘 다 BEGIN부터 다음 END까지 모든 것을 메모리에 저장해야 합니다. 따라서 첫 번째 줄에 BEGIN이 포함되어 있지만 END가 없는 큰 파일이 있는 경우 전체 파일이 무의미하게 메모리에 저장됩니다.
이 문제를 해결하는 유일한 방법은 파일을 두 번 처리하는 것입니다. 물론 이는 입력이 일반 파일(예: 파이프가 아님)인 경우에만 수행할 수 있습니다.
답변4
GNU awk 방법. 시작 헤더가 발견되면 특정 변수를 설정하여 결과를 얻습니다. 편의상 일부 변수는 단축될 수 있습니다.
$ awk '/BEGIN/{a[i++]=$0;flag=1;next};flag==1{a[i++]=$0;if($0~/END/){print_array=1; nextfile;} }; END{if(print_array) for(j=0;j<=i;j++)print a[j]}' input.txt
***** BEGIN *****
BASH is awesome
BASH is awesome
***** END *****
END 플래그가 없기 때문에 결과는 예상대로 null입니다.
$ awk '/BEGIN/{a[i++]=$0;flag=1;next};flag==1{a[i++]=$0;if($0~/END/){print_array=1; nextfile;} }; END{if(print_array) for(j=0;j<=i;j++)print a[j]}' input2.txt