시작 패턴과 끝 패턴 사이에 줄을 인쇄합니다. 그러나 끝 패턴이 없으면 인쇄하지 않습니다.

시작 패턴과 끝 패턴 사이에 줄을 인쇄합니다. 그러나 끝 패턴이 없으면 인쇄하지 않습니다.

일치하는 두 패턴 사이의 선을 찾고 있습니다. 시작 또는 끝 패턴이 누락된 경우 선이 인쇄되지 않습니다.

올바른 입력:

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

관련 정보