bash 쉘에서 파일의 섹션을 grep하는 방법


5

어떤 string1의 발생과 어떤 string2의 (N 번째) 발생 사이의 줄을 어떻게 grep 할 수 있습니까?

예 :

파일에 행이있는 경우 :

에이

기음

이자형

에프


기음
이자형

선을 굵은 체로 만들고 싶습니다 (B로 시작하고 E로 끝나는 선).

grep을 사용하여이 작업을 수행 할 수 있습니까? 또는 다른 유닉스 명령 줄 도구?


이것은 sed에 대한 테스트로 들립니다. 그러나 내 sed-fu는 니콜만큼 좋지 않으므로 가까운 경기를 겨냥하고 있습니다. 수퍼 유저 /questions/513393/converting-strings-in-input-file
Hennes

답변:


9

grep 이 작업에 적합하지 않은 경우 하나의 도구를 "위로"올려야합니다.

sed -n '/^B/,/^E/p' infile

산출:

B
C
D
E
B
C
E

N 번째 요구 사항에 관해서는, 한 도구를 "위로"즉 awk로 다시 이전하는 것이 가장 쉽다고 생각합니다.

awk '/^B/ { f = 1; n++ } f && n == wanted; /^E/ { f = 0 }' wanted=2 infile

산출:

B
C
E

깃발 f 언제 설정 되나요? /^B/ 때 발생하고 설정되지 않은 /^E/ sed 표기법이 작동하는 것과 같은 방식으로 진행됩니다. n 얼마나 많은 블록이 통과되었는지, 언제 f == 1 && n == wanted 가 true이면 기본 블록이 실행됩니다 ( { print $0 } ).


정확히 무엇을하는지 설명해 주시겠습니까? 나는 send가 입력 스트림을 처리한다는 것을 이해한다. 여기서 구문을 추측하는 것은 정규 표현식 / ^ B / to [,] regexp / ^ E (인쇄하지 말 것) [p] /?
epeleg

발견 된 두 블록 사이에 분리 기호를 삽입하는 방법이 있습니까?
epeleg

@epeleg : sed 예제는 여러분이 가정 할 때 작동합니다. 범위에 뒤 따르는 모든 명령은 입력이 그 범위에있는 동안 실행됩니다. 조금 sed로 구분 기호를 삽입하기가 복잡하기 때문에 대신 awk를 사용하고 싶습니다. 최신 편집을 참조하십시오.
Thor

3

@ Thor 's sed 명령은 구타 될 수 없지만 다음 명령으로 perl 스크립트 괄호 안에 질문의 일부를 처리하려고합니다. "... (N 번째) 발생 ...".

용법:

./script <start-regex> <end-regex> [N]

질문에있는 파일의 예 :

$ ./script "B" "E" < examplefile
B
C
D
E
B
C
E

$ ./script "B" "E" 2 < examplefile
B
C
D
E
F
G
B
C
E

어떤 오류 검사도 없으며 스크립트는 욕심이 없습니다, 즉 A B C D E E FB C D E N = 1로 grep 될 것입니다.


#!/usr/bin/perl

if ($ARGV[2] != "") { $n = $ARGV[2] } else { $n = 1 }
$begin_str = $ARGV[0];
$end_str = $ARGV[1];

while(<STDIN>) {
  if($_ =~ $begin_str) { $flag=1 }             # beginning of match, set flag    
  if($_ =~ $end_str && $flag eq 1) { $i++ }    # i-th occurence of end string

  if($i eq $n) {                               # end of match after n occurences of end string
    $flag=2;
    $i=0; 
  }

  if ($flag ge 1) {                            # append currrent line to matching part
    $out.=$_;
  }

  if($flag eq 2) {                             # after detection of end of match, print complete match
    print $out;
    # print "---\n";                           # separator after a match
    $out="";
    $flag=0;
  }

}

감사. 나는 이것을 미래에도 사용할 수 있지만, 지금은 sed 해결책이 갈 길이라고 믿습니다.
epeleg

1
이 코드를 다시 보면, 필자는 정확한 요구에 맞게 수정할 수 있기 때문에 정말 좋아합니다. (예를 들어 각 줄의 시작 부분에 반복 번호를 추가하는 것처럼).
epeleg

줄 단위로 인쇄하는 대신 $ out에 연결하는 이유를 설명 할 수 있습니까?
epeleg

@epeleg : 줄 단위로 인쇄 할 수 없습니다. (처음에는 그랬습니다) A B D 결과는 B D, "종료 종결 자"는 없지만 E. 그 외에도, 이것은 당신에게 "그 두 발견 된 블록들 사이의 분리 기호"를 넣는 쉬운 방법을 제공합니다. (저는 이것을 지금 스크립트에 주석으로 포함 시켰습니다.)
mpy

"끝없는 종결 자"에 대한 좋은 지적. 감사.
epeleg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.