grep 또는 awk를 사용하여 패턴 사이의 텍스트 블록/라인을 인쇄하세요.

grep 또는 awk를 사용하여 패턴 사이의 텍스트 블록/라인을 인쇄하세요.

내 파일은 file.txt다음과 같습니다.

[NamesA]
Andreas
Alex

[NamesB]
Bernd
Bruno

[NamesC]
Casper

[NamesD]
Doris

grep다음 3가지 다른 출력을 달성하기 위해 이것을 bash 스크립트에서 사용하거나 사용하고 싶습니다 .awk

  1. 산출

    [NamesB]   
    Bernd   
    Bruno
    
  2. 산출

    [NamesB]
    Bernd
    Bruno
    
    [NamesC] 
    Casper
    
  3. 산출

    [NamesD]
    Doris
    

나는 시도했다:

grep  -oP '\[NamesB\].*?' file.txt

하지만 [NamesB]대신 다음 텍스트 블록만 가져옵니다. 나는 텍스트를 바로 뒤에 가져왔지만 새 줄에는 가져오지 못했습니다.

그게 다야. 으로 시작하는 다음 줄을 최소한 모두 얻을 수 있다면 [NamesB]그것조차도 작동하지 않습니다.

  • 따라서 1.의 출력은 [NamesB]다음 항목으로 시작하고 끝나는 모든 항목을 인쇄하여 가장 간단할 수 있다고 상상할 수 있습니다 [.
  • 2번이 출력 1번과 유사하지만 grep2번 실행되는 것을 상상할 수도 있습니다. 한 번 [NamesB], 그 다음에는[NamesC]

[하지만 다음이 없기 때문에 3.에서는 이것이 어떻게 작동합니까 ? 그리고 로 시작하는 알 수 없는 다음 블록이 있을 수도 있습니다 [.

그런 다음 명령은 [NamesB]또는로 시작하는 텍스트 인쇄를 시작하고 다음 여는 대괄호 [또는 파일 끝에서 중지해야 합니다.

추신: 비슷한 질문을 게시하고 해결책을 찾았지만전체 텍스트 줄. 이 질문에서는 다른 상황, 즉 한 줄이 아닌 텍스트 블록이 있습니다.

답변1

인쇄할 레코드를 선택하기 위한 요구 사항이 명확하지 않지만 아마도 이것이 awk로 수행하려는 작업일 수 있습니다.

출력 1, 옵션 1(한 번에 한 줄씩 읽기):

$ awk '/^\[/{f=(/^\[NamesB]/)} f' file.txt
[NamesB]
Bernd
Bruno

출력 1, 옵션 2(한 번에 1개의 여러 줄 레코드 읽기)

$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 == "[NamesB]"' file.txt
[NamesB]
Bernd
Bruno

출력 2, 옵션 1(NamesB 레코드와 그 뒤의 레코드 인쇄):

$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 == "[NamesB]"{c=2} c&&c--' file.txt
[NamesB]
Bernd
Bruno

[NamesC]
Casper

출력 2, 옵션 2(입력 위치에 관계없이 NamesB 및 NamesC 레코드 인쇄):

$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 ~ /^\[Names[BC]]$/' file.txt
[NamesB]
Bernd
Bruno

[NamesC]
Casper

출력 3, 옵션 1(NamesD 레코드 인쇄):

$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 == "[NamesD]"' file.txt
[NamesD]
Doris

출력 3, 옵션 2(이름이 무엇이든 입력의 네 번째 레코드를 인쇄합니다):

$ awk -v RS= -v ORS='\n\n' -F'\n' 'NR == 4' file.txt
[NamesD]
Doris

또한 다음과 관련하여:

최소한 [NamesB]로 시작하는 다음 줄을 모두 얻을 수 있다면

다음은 트릭을 수행합니다.

$ awk -v RS= -v ORS='\n\n' -F'\n' '$1 == "[NamesB]"{f=1} f' file.txt
[NamesB]
Bernd
Bruno

[NamesC]
Casper

[NamesD]
Doris

물론, 다양한 기준에 따라 출력을 생성하기 위해 다른 많은 스크립트를 작성할 수 있으며, 올바른 스크립트는 출력할 청크를 선택할 때의 요구 사항에 따라 달라집니다.

답변2

Raku(이전 Perl_6) 사용

~$ raku -e 'for slurp.split("\n\n") { .put if / \[ NamesA \]  /};'   file

#OR

~$ raku -e '.put if / \[ NamesA \]  / for slurp.split("\n\n");'   file

위 내용은 Perl 계열의 프로그래밍 언어인 Raku로 작성된 답변입니다. 즉, 파일은 두 개의 연속된 개행 문자를 slurp사용하여 한 번에 메모리에 기록 됩니다 . 결과 요소(레코드)는 다음을 사용하여 반복됩니다 . 필수 정규식과 일치하는 항목이 발견되고 요소(레코드)가 out됩니다 .split\n\nforifput

입력 예:

[NamesA]
Andreas
Alex

[NamesB]
Bernd
Bruno

[NamesC]
Casper

[NamesD]
Doris

예제 출력:

[NamesA]
Andreas
Alex

|정규식 일치자에서 OR 기호를 사용하면 여러 레코드를 반환할 수 있습니다. 반환값을 적절하게 분리하려면 $_.put또는 부분을 다시 작성하고 각 레코드에 후행 개행 문자를 채울 수 있습니다..putput "$_\n"

~$ raku -e 'put "$_\n" if / \[ NamesA | NamesB \]  / for slurp.split("\n\n");'   file
[NamesA]
Andreas
Alex

[NamesB]
Bernd
Bruno

참고: 정규식 일치자는 레코드의 모든 행이 될 수 있습니다. 첫 번째 줄을 구체적으로 일치시키려면 /^ \[ NamesA \] $$ /여기서는 ^문자열의 시작을 의미하고 $$줄의 끝을 의미합니다.

https://docs.raku.org
https://raku.org

답변3

다음을 사용하여 모든 블록(예: NamesA)을 추출할 수 있습니다.

$ awk '/^\[NamesA/{p=1; print; next} /^\[/{p=0}; p>0{print}' input_file
[NamesA]
Andreas
Alex

코드에 표시된 대로 블록 헤더의 첫 번째 문자인 [를 이스케이프해야 합니다.

이 한 줄을 사용하면 필요에 맞게 출력 조합을 인쇄할 수 있습니다.

관련 정보