일치하는 두 패턴 사이의 선을 찾고 있습니다. 시작 또는 끝 패턴이 누락된 경우 선이 인쇄되지 않습니다.
올바른 입력:
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