파일을 구문 분석하고 특정 두 줄 사이의 데이터 조각을 인쇄하고 싶습니다. "범위 시작"부터 "범위 끝"까지. 단, "범위 끝"이 존재하는 경우에만 해당됩니다.
소스 파일이 다음과 같은 경우:
[This is the start] of some data
this is information
this is more information
This is does not contain the ending required
[This is the start] of some other data
this is info I want
this is info I want
[This is the ending I was looking for]
다음과 같이 인쇄되어야 합니다.
[This is the start] of some other data
this is info I want
this is info I want
[This is the ending I was looking for]
grep을 사용하여 필요한 데이터를 찾아 위쪽으로 인쇄할 수 있었지만 줄 수는 고정되어 있었습니다.
데이터 행 수가 일정하지 않은 경우 grep 또는 sed를 사용하여 끝 행에서 시작하여 주어진 문자열의 다음 항목을 찾고 원하는 특정 범위를 캡처할 수 있는 방법이 있습니까?
데이터 세그먼트의 "범위 시작"은 "범위 시작"과 "범위 끝" 지점 사이의 모든 데이터와 함께 인쇄되어야 하며 "범위 끝" 일치는 전체 행 범위를 인쇄해야 하는지 여부를 결정합니다. 범위(데이터 세그먼트)에 지정된 끝이 없으면 인쇄되지 않아야 합니다. 여러 세그먼트에 끝점이 있으면 끝점을 포함하는 모든 세그먼트가 인쇄되어야 합니다. 입력 파일에 끝은 있지만 시작이 없거나, 단일 시작에 여러 끝이 있는 경우가 없습니다.
두 패턴 사이(및 포함)의 선을 인쇄합니다.일치하는 첫 번째 줄에서 인쇄를 시작하고 첫 번째 종료 세그먼트를 찾을 때까지 계속 인쇄하므로 문제가 해결되지 않습니다. 지정된 종료문이 포함된 세그먼트만 인쇄해야 합니다.
답변1
사용 sed
:
$ sed -n '/This is the start/{h;d;}; H; /This is the ending/{x;p;}' file
[This is the start] of some other data
this is info I want
this is info I want
[This is the ending I was looking for]
주석이 달린 sed
스크립트:
/This is the start/{ # We have found a start
h; # Overwrite the hold space with it
d; # Delete from pattern space, start next cycle
};
H; # Append all other lines to the hold space
/This is the ending/{ # We have found an ending
x; # Swap pattern space with hold space
p; # Print pattern space
};
이 스크립트가 하는 일은 모든 줄을 "예약된 공간"( 의 공통 버퍼 sed
)에 저장하는 것입니다. 그러나 일단 "시작 줄"을 찾으면 해당 공간을 재설정합니다. "끝 라인"을 찾으면 저장된 데이터가 인쇄됩니다.
"시작 라인" 앞에 "끝 라인"이 있고 사이에 "시작 라인"이 없는 두 개의 "엔드 라인"이 발견되면 이는 중단됩니다.
awk
위와 동일한 프로세스를 수행하는 프로그램 sed
:
$ awk '/This is the start/ { hold = $0; next }
{ hold = hold ORS $0 }
/This is the ending/ { print hold }' file
(위와 동일한 출력)
답변2
다중 START
및 END
패턴의 경우 다음을 수행할 수 있습니다.
sed 'H;/START/h;/END/!d;x;/START/!d' infile
이는 이전 버퍼에 무조건적으로 행을 누적하고, H
행이 발견될 때마다 이를 덮어쓰며(즉, 가장 최근 행의 데이터만 유지), 행이 포함되지 않은 경우 패턴 공간을 삭제하고(여기서 루프 다시 시작) 그렇지 않으면 e 변경 버퍼를 제거하고 패턴 공간을 다시 제거합니다. 이번에는 패턴 공간이 포함되어 있지 않으면 나머지는 자동으로 인쇄됩니다.h
START
START
d
END
x
d
START
답변3
tac
행 순서를 바꾸는 데 사용됩니다 .
파일을 반전하는 경우 tac
(마지막 줄을 먼저 인쇄하는 등) 끝 패턴에서 시작 패턴까지 영역을 추출할 수 있습니다. 그런 다음 tac
다시 사용하여 출력 라인을 정방향 순서로 인쇄합니다.
tac file.txt | awk '/^\[This is the ending I was looking for]/,/^\[This is the start]/ { print $0 }' | tac
화면에 더 잘 맞도록 형식이 지정된 동일한 코드:
tac file.txt | \
awk '/^\[This is the ending I was looking for]/,/^\[This is the start]/ { print $0 }' | \
tac
{ print $0 }
awk
기본 동작이므로 이 특정 명령에는 필요하지 않습니다 .
tac file.txt | \
awk '/^\[This is the ending I was looking for]/,/^\[This is the start]/' | \
tac
안타깝게도 Mac을 사용하는 경우 tac
기본적으로 설치되지 않습니다.
답변4
awk를 사용하는 솔루션은 다음과 같습니다.
rstart='^[[]This is the start[]]'
rend='[[]This is the ending I was looking for[]]'
awk '$0~rstart{i=1;a=""}
$0~rstart,$0~rend && i==1 {a = a ((a=="")?"":ORS) $0}
$0~rend{i=0;print(a)}
' rstart="$rstart" rend="$rend" infile
대괄호는 백슬래시 사용을 방지하기 [[]
위해 및 와 일치합니다 (경우에 따라 실패할 수 있음).[]]
\\[
주요 아이디어는 변수 i
(포함)를 부울로 사용하여 인쇄할 범위의 각 줄을 포함하거나 제외하는 것입니다. 전체 범위는 변수에 누적됩니다 a
. 변수가 a
비어 있지 않으면( ((a=="")?"":ORS)
) ORS(출력 레코드 구분 기호)로 구분됩니다.
그러면 다음이 인쇄됩니다:
[This is the start] of some other data
this is info I want
this is info I want
[This is the ending I was looking for]
요구 사항이 시작 태그와 끝 태그를 인쇄하지 않는 것이라면 동일한 코드를 사용하되 라인 1과 3을 바꿉니다.
awk '$0~rend{i=0;print(a)}
$0~rstart,$0~rend && i==1 {a = a ((a=="")?"":RS) $0}
$0~rstart{i=1;a=""}
' rstart="$rstart" rend="$rend" infile
다음을 인쇄합니다:
this is info I want
this is info I want