여러 줄의 gensub

여러 줄의 gensub

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

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

위의 숫자 "98"과 일치시키기 위해 awk 및 gensub만 사용하고 싶습니다. 지금까지 아래 코드가 있는데 작동하지 않는 것 같습니다. 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
    

    Perl 은 -n입력 파일을 한 줄씩 읽고 에서 제공하는 스크립트를 적용하도록 지시합니다 -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]+)"

그리고 당신은 결과를 얻을 것입니다.

관련 정보