여러 줄의 Gensub

여러 줄의 Gensub

다음과 같은 임의의 줄이 많은 파일이 있습니다.

aaa bbb
ccc ddd
eee mark: 98 fff
ggg ggg jjjj iii
jjj kkkk

awk와 gensub만을 사용하여 위의 숫자 "98"을 일치시키고 싶습니다. 지금까지 아래 코드가 있는데, gensub가 "\n"을 다른 문자로 처리하도록 해야 하기 때문에 작동하지 않는 것 같습니다.

cat file.txt | awk 'printf(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}'

위 코드의 출력은 "98"만 필요합니다. 어떻게 해야 하나요?

편집하다

s 또는 m 수정자를 사용하더라도 내가 아는 한 "s" 수정자는 정규 표현식을 처리해야 하기 때문에 작동하지 않습니다. \n을 포함한 모든 문자로.

답변1

awk입력이 여러 줄 문자열로 처리된다고 생각하는 것 같습니다 . 그러나 실제로는 그렇지 않습니다. 파일에서 awk 스크립트를 실행하면 해당 스크립트가 적용됩니다.파일의 각 줄에각기. 따라서 행당 gensub한 번씩 실행합니다. 실제로 원하는 것을 할 수 있지만 awk실제로는 해당 작업에 가장 적합한 도구는 아닙니다.

내가 아는 한, 당신은 큰 파일을 가지고 있고 다음 숫자 mark:와 공백만 인쇄하려고 합니다. 그렇다면 이 모든 방법이 주변에 머무르는 것보다 간단합니다 gensub.

  1. grepPerl 호환 정규 표현식과 함께 사용됨( -P)

    $ grep -oP 'mark:\s*\K\d+' file 
    98
    

    -o제조업체는 grep라인에서 일치하는 부분만 인쇄합니다. 이는 \K"이 지점 이전에 일치하는 모든 항목을 무시합니다"를 의미하는 PCRE 구성입니다.

  2. sed

    $ sed -n 's/.*mark:\s*\([0-9]\+\).*/\1/p' file
    98
    

    정상적인 출력을 억제합니다 -n. 교체가 성공한 경우에만 p마지막에 인쇄됩니다. sed정규식 자체는 다음 숫자 문자열 mark:과 0개 이상의 공백 문자를 캡처하고 전체 줄을 캡처된 콘텐츠로 바꿉니다.

  3. 진주

    $ perl -ne 'print if s/.*mark:\s*(\d+).*/$1/' file
    98
    

    -nPerl에게 입력 파일을 한 줄씩 읽고 주어진 스크립트를 적용하도록 지시합니다 -e. 스크립트는 교체가 성공한 모든 행을 인쇄합니다.

정말 정말 사용하고 싶다면 gensub다음과 같이 하세요.

$ awk '/mark:/{print gensub(/.*mark:\s*([0-9]+).*/,"\\1","g")}' file
98

개인적으로 저는 awk에서 이 작업을 수행합니다.

$ awk '/mark:/{gsub(/[^0-9]/,"");print}' file
98

awk가 여러 줄의 입력을 허용하도록 하려는 것 같으므로 다음과 같이 할 수 있습니다(파일에 NULL 문자가 없다고 가정).

$ awk '{print(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}' RS='\0' file
98

RS='\0'입력 레코드 구분 기호(즉, 정의된 "라인" awk)를 로 설정합니다 \0. 파일에 이러한 문자가 없으므로 awk전체 내용을 즉시 읽습니다.

답변2

이를 작동시키기 위한 최소한의 변경 사항은 다음과 같습니다.

cat file | awk '/mark:/{printf( "%s\n",gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}'

/mark:/는 "mark:"가 포함된 줄을 선택합니다.
그런데 왜 printf가 필요합니까? 이것은 또한 작동합니다:

cat file | awk '/mark:/{print(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}'

하지만 그것은 "고양이의 쓸모없는 사용", awk는 파일에서 직접 읽을 수 있기 때문입니다.

awk '/mark:/{print(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}' file

편집하다:

사용자 요청별: 파일 및 문자열에 정규식을 사용하는 방법.

글쎄, 당신이 설정한 규칙에 따르면: gensub만을 사용하는 awk에서는 불가능합니다.
또한 일치의 개념은 .*mark: ([0-9]+).*모든 것을 괄호 안의 일치 항목으로 바꾸는 것입니다. 즉, 일부를 추출하려면 전체 파일을 일치시켜야 함을 의미합니다. 이것이 grep이 만들어진 이유 중 하나입니다.

그냥 사용:

grep -oP "mark: \K([0-9]+)" file

또는:

echo "$string" | grep -oP "mark: \K([0-9]+)"

당신은 결과를 얻을 것이다.

관련 정보