다음과 같은 임의의 줄이 많은 파일이 있습니다.
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
.
grep
Perl 호환 정규 표현식과 함께 사용됨(-P
)$ grep -oP 'mark:\s*\K\d+' file 98
-o
제조업체는grep
라인에서 일치하는 부분만 인쇄합니다. 이는\K
"이 지점 이전에 일치하는 모든 항목을 무시합니다"를 의미하는 PCRE 구성입니다.sed
$ sed -n 's/.*mark:\s*\([0-9]\+\).*/\1/p' file 98
정상적인 출력을 억제합니다
-n
. 교체가 성공한 경우에만p
마지막에 인쇄됩니다.sed
정규식 자체는 다음 숫자 문자열mark:
과 0개 이상의 공백 문자를 캡처하고 전체 줄을 캡처된 콘텐츠로 바꿉니다.진주
$ perl -ne 'print if s/.*mark:\s*(\d+).*/$1/' file 98
-n
Perl에게 입력 파일을 한 줄씩 읽고 주어진 스크립트를 적용하도록 지시합니다-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]+)"
당신은 결과를 얻을 것이다.