AWK

AWK

"--"로 구분된 텍스트 줄("단락")을 인쇄하는 프로그램이 있습니다. 예를 들어 인쇄될 수 있습니다.

--
are you happy
--
I am hungry
are you
--
are(you hungry
too

나는 이것을 다른 프로그램(아마도 sed?)으로 파이프하고 주어진 단어(예: "are")로 시작하는 단락만 반환하고 싶습니다. 따라서 위의 경우 "are"로 시작하는 단락을 얻으면 다음과 같은 결과를 얻을 수 있습니다.

--
are you happy
--
are(you hungry
too

프로그램은 매우 많은 수의 "문단"을 인쇄하지만 작은 부분만 일치할 것으로 예상합니다. 이것이 바로 프로그램의 출력을 스트리밍 방식으로 필터링할 수 있기를 원하는 이유입니다(모든 것을 하나로 작성하는 것을 피하기 위해). 큰 파일을 필터링한 다음 필터링하세요).

답변1

AWK

GNU awk 또는 mawk 사용:

$ awk '$1~"^"word{printf("--\n%s",$0)}' word='are' RS='--\n' infile
--
are you happy
--
are(you hungry
too

이는 변수 단어를 레코드 시작 부분에서 일치시킬 단어로 설정하고 RS(레코드 구분 기호)를 "--"로 설정한 다음 새 줄을 추가합니다 \n. 그런 다음 ( )와 일치하는 단어로 시작하는 레코드에 대해 $1~"^"word형식이 지정된 레코드를 인쇄합니다. 형식은 "--"로 시작하고 발견된 정확한 레코드를 포함하는 새 줄을 갖는 것입니다.

그렙

(GNU 옵션 -z) grep을 사용하십시오.

grep -Pz -- '--\nare(?:[^\n]*\n)+?(?=--|\Z)' infile
grep -Pz -- '(?s)--\nare.*?(?=\n--|\Z)\n' infile
grep -Pz -- '(?s)--\nare(?:(?!\n--).)*\n' infile

설명 다음 설명에서는 PCRE 옵션을 (?x)사용하여 실제(작동하는) 정규 표현식과 함께 (큰) 설명 주석(및 공백)을 인라인으로 추가합니다. 주석(및 대부분의 공백)(다음 개행까지)이 제거되면 결과 문자열은 여전히 ​​동일한 정규식입니다. 이를 통해 작업 코드의 정규식에 대한 자세한 설명이 가능합니다. 이렇게 하면 코드 유지 관리가 더 쉬워집니다.

옵션 1 정규식 (?x)--\nare(?:[^\n]*\n)+?(?=--|\Z)

(?x)   # match the remainder of the pattern with the following
       # effective flags: x
       #      x modifier: extended. Spaces and text after a # 
       #      in the pattern are ignored
--     # matches the characters -- literally (case sensitive)
\n     # matches a line-feed (newline) character (ASCII 10)
are    # matches the characters are literally (case sensitive)
(?:    #      Non-Capturing Group (?:[^\n]*\n)+?
[^\n]  #           matches non-newline characters
*      #           Quantifier — Matches between zero and unlimited times, as
       #           many times as possible, giving back as needed (greedy)
\n     #           matches a line-feed (newline) character (ASCII 10)
)      #      Close the Non-Capturing Group
+?     # Quantifier — Matches between one and unlimited times, as
       # few times as possible, expanding as needed (lazy)
       # A repeated capturing group will only capture the last iteration.
       # Put a capturing group around the repeated group to capture all
       # iterations or use a non-capturing group instead if you're not
       # interested in the data
(?=    # Positive Lookahead (?=--|\Z)
       # Assert that the Regex below matches
       #      1st Alternative --
--     #           matches the characters -- literally (case sensitive)
|      #      2nd Alternative \Z
\Z     #           \Z asserts position at the end of the string, or before
       #           the line terminator right at the end of the 
       #           string (if any)
)      #      Closing the lookahead.

옵션 2 정규식 (?sx)--\nare.*?(?=\n--|\Z)\n

(?sx)  # match the remainder of the pattern with the following eff. flags: sx
       #        s modifier: single line. Dot matches newline characters
       #        x modifier: extended. Spaces and text after a # in 
       #        the pattern are ignored
--     # matches the characters -- literally (case sensitive)
\n     # matches a line-feed (newline) character (ASCII 10)
are    # matches the characters are literally (case sensitive)
.*?    # matches any character 
       #        Quantifier — Matches between zero and unlimited times,
       #        as few times as possible, expanding as needed (lazy).
(?=    # Positive Lookahead (?=\n--|\Z)
       # Assert that the Regex below matches
       #        1st Alternative \n--
\n     #               matches a line-feed (newline) character (ASCII 10)
--     #               matches the characters -- literally.
|      #        2nd Alternative \Z
\Z     #               \Z asserts position at the end of the string, or
       #               before the line terminator right at
       #               the end of the string (if any)
)      # Close the lookahead parenthesis.
\n     #        matches a line-feed (newline) character (ASCII 10)
 

옵션 3 정규식 (?xs)--\nare(?:(?!\n--).)*\n

(?xs)  # match the remainder of the pattern with the following eff. flags: xs
       # modifier x : extended. Spaces and text after a # in are ignored
       # modifier s : single line. Dot matches newline characters
--     # matches the characters -- literally (case sensitive)
\n     # matches a line-feed (newline) character (ASCII 10)
are    # matches the characters are literally (case sensitive)
(?:    # Non-capturing group (?:(?!\n--).)
(?!    #      Negative Lookahead (?!\n--)
       #           Assert that the Regex below does not match
\n     #                matches a line-feed (newline) character (ASCII 10)
--     #                matches the characters -- literally
)      #      Close Negative lookahead
.      #      matches any character
)      # Close the Non-Capturing group.
*      # Quantifier — Matches between zero and unlimited times, as many
       # times as possible, giving back as needed (greedy)
\n     # matches a line-feed (newline) character (ASCII 10)

sed

$ sed -nEe 'bend
            :start  ;N;/^--\nare/!b
            :loop   ;/^--$/!{p;n;bloop}
            :end    ;/^--$/bstart'           infile

답변2

GNU를 사용 awk하거나 다음 을 수행하십시오 mawk.

$ awk -v word="are" -v RS='--\n' -v ORS='--\n' '$1 ~ "^" word "[[:punct:]]?"' file
are you happy
--
are(you hungry
too
--

입력 및 출력에 대한 레코드 구분 기호 --와 개행 문자를 설정합니다. 각 단락의 첫 번째 단어는 에서 확인할 수 있습니다 $1. 우리는 그것을 주어진 단어와 일치시킵니다(구두점이 뒤따를 수도 있음). 일치하면 단락을 인쇄합니다.

출력의 단락 표시는 출력에 사용한 것처럼 각 단락의 시작 부분이 아닌 끝 부분에 배치됩니다 ORS.


sed스크립트 사용 :

:top
/^--/!d;                   # This is not a new paragraph, delete
N;                         # Append next line
/^--\nare[[:punct:]]?/!d;  # This is not a paragraph we want, delete
:record
n;                         # Output line, get next
/^--/!brecord;             # Not yet done with this record, branch to :record
btop;                      # Branch to :top

달리기:

$ sed -E -f script.sed file
--
are you happy
--
are(you hungry
too

또는 쉘 변수를 사용하여 한 줄의 코드로 사용합니다 $word.

sed -E -e ':t;/^--/!d;N;' \
       -e "/^--\n$word[[:punct:]]?/!d" \
       -e ':r;n;/^--/!br;bt' file

답변3

나도 알아요, 이것은 오래된 질문이지만, 이 모든 루프, 분기 및 패턴이 저글링되는 것을 보면 간단한

sed '/^--$/!{H;$!d;};x;/^--\nare/!d'

자연스러운 방법으로 동일한 작업을 수행하십시오.

sed줄 단위 흐름 편집기이므로 여러 줄의 내용이 필요한 경우 H단락 표시( ^--$) 의 예약된 공간에 해당 줄을 수집하고 x버퍼를 변경하고 단락이 인쇄되는지 테스트합니다( 한 줄 뒤에 ^--\nare한 줄이 있음을 의미). --출발선으로 are). x단락 태그 예약 공간이 이미 미리 로드되어 있습니다.

확장 기능이 포함된 GNU 도구도 필요하지 않으며, 프로그래밍 기술도 필요하지 않습니다. 단지 참여만 하면 됩니다 sed.

답변4

귀하의 질문을 읽은 후에도 같은 느낌이 듭니다.~해야 한다grep+를 사용하여 해결할 수 있습니다 .PCRE.

  • @issac의 도움 덕분에 방법 #1이 문제를 해결했습니다.
  • (?s)방법 #2는 인라인 수정자( ) 및 예측( ) 을 사용하는 방법을 보여줍니다 ?!....
  • 내 원래 솔루션(#3)은 아래 섹션에서 강조한 유형을 제외하고 대부분의 경우 잘 작동합니다.

그렙 방법 #1

$ grep -Pzo -- '--\nare([^\n]*\n)+?(?=--|\Z)' afile

어떻게 작동하나요?

그렙 스위치
  • -P- PCRE 확장 활성화
  • -z- 입력을 여러 줄로 처리하고 대신 NUL을 사용하세요 \n(개행 문자)
  • -o- 일치하는 항목만 표시
정규식
  • --\nare([^\n]*\n)+?(?=--|\Z)
    • 이중 대시와 그 뒤에 하나의 are, 그 다음 0개 이상의 개행이 아닌 연속 또는 개행 문자와 일치합니다.
    • +?1 이상과 일치하지만 욕심이 많지 않으므로 공격적으로 계속하지 않습니다 .
    • 마지막으로 (?=--|\Z)블록 끝 가드는 다음 이중 대시 --또는 파일 끝( \Z)을 찾습니다.

그렙 방법 #2

이 방법은 DOTALL 인라인 수정자를 사용하여 .줄 바꿈(`n`)을 일치시킵니다.

$ grep -Pzo -- '(?s)--\nare((?!\n--).)+\n' afile

어떻게 작동하나요?

그렙 스위치
  • -P- PCRE 확장 활성화
  • -z- 입력을 여러 줄로 처리하고 대신 NUL을 사용하세요 \n(개행 문자)
  • -o- 일치하는 항목만 표시
정규식
  • (?s)- 인라인 수정자 DOTALL - 모든 점이 줄 바꿈과 일치합니다.
  • --\nare- 개행 문자 뒤에 오는 문자와 일치합니다.are
  • ((?!\n--).)+\n.-정방향 검색에서 . 문자가 (?!\n--)발견되지 않는 한 \n--일치합니다. 전체 일치 블록에는 +개행 문자가 뒤따르는 하나 이상의 ( )가 있어야 합니다 \n.

grep 방법 #3(원본)

grepPCRE 확장( )을 활용한 -P솔루션 입니다 . 이 방법은 제공된 모든 예제에 작동하지만 다음과 같은 예제에서는 실패합니다.

--
are
some-other-dasher

그러나 대부분의 경우 이를 처리해야 한다고 상상할 수 있습니다.

$ grep -Pzo -- '--\nare[^\r\n]+[^-]+' afile
--
are you happy

--
are(you hungry
too

어떻게 작동하나요?

그렙 스위치
  • -P- PCRE 확장 활성화
  • -z- 입력을 여러 줄로 처리하고 대신 NUL을 사용하세요 \n(개행 문자)
  • -o- 일치하는 항목만 표시
정규식
  • '--\nare[^\r\n]+[^-]+'
    • 개행 문자와 단어가 뒤에 오는 이중 대시와 일치합니다 are.
    • are그런 다음 개행 문자를 만날 때까지 나머지 줄을 계속 인쇄합니다 .
    • 그런 다음 일련의 대시가 나타날 때까지 문자를 인쇄합니다.

인용하다

관련 정보