AWK : 회선 패턴에서 캡처 된 그룹에 액세스


229

awk 명령이 있으면

pattern { ... }

패턴이 캡처 그룹을 사용하는 경우 블록에서 캡처 된 문자열에 어떻게 액세스 할 수 있습니까?



때로는 (간단한 경우) 필드 구분 기호 ( FS) 를 조정하고 a와 일치시킬 항목을 선택할 수 $field있습니다. 입력을 미리 포맷하면 도움이 될 수 있습니다.
— Krzysztof Jabłoński

1
중복 질문에 대한 더 나은 답변 이 있습니다 .
— Samuel Edwin Ward

2
사무엘 에드윈 워드 : 좋은 답변입니다! 그러나 그것은 또한 필요 gawk(이것은 사용하기 때문에 gensub).
— rampion

답변:


176

그것은 기억의 길을 걷는 것입니다 ...

오래 전에 awk를 perl로 바꿨습니다.

분명히 AWK 정규식 엔진은 그룹을 캡처하지 않습니다.

다음과 같은 것을 사용하는 것이 좋습니다.

perl -n -e'/test(\d+)/ && print $1'

-n 플래그는 perl이 awk처럼 모든 행을 반복하도록합니다.


3
분명히 누군가 동의하지 않습니다. 이 웹 페이지는 2005 년에 있습니다. tek-tips.com/faqs.cfm?fid=5674 awk에서 일치하는 그룹을 재사용 할 수 없음을 확인합니다.
— Peter Tillemans

3
나는 거의 모든 유스 케이스에서 ack보다 'perl -n -p -e ...'를 선호한다.
— Peter Tillemans

15
gawk! = awk. 도구는 다르며 gawk대부분의 경우 기본적으로 사용할 수 없습니다.
— Oli

6
OP는 구체적으로 awk 솔루션을 요청했기 때문에 이것이 대답이라고 생각하지 않습니다.
— Joppe

6
@Joppe 솔루션이 없으면 awk 솔루션을 제공 할 수 없습니다. 3 행에서 AWK가 그룹 캡처를 지원하지 않는다고 설명하고 대안을 제시했습니다.이 답변이 승인되었으므로 OP가 분명히 감사했습니다. 이 질문에 어떻게 더 잘 대답 할 수 있습니까?
— 피터 틸만

335

gawk를 사용하면 match 기능을 괄호로 묶은 그룹을 캡처 .

gawk 'match($0, pattern, ary) {print ary[1]}' 

예:

echo "abcdef" | gawk 'match($0, /b(.*)e/, a) {print a[1]}' 

출력 cd.

해당 기능을 구현하는 gawk의 특정 사용에 유의하십시오.

휴대용 대안을 당신이 유사한 결과를 얻을 수 있습니다 match()및substr .

예:

echo "abcdef" | awk 'match($0, /b[^e]*/) {print substr($0, RSTART+1, RLENGTH-1)}'

출력 cd.


4
그렇습니다. gxxx 변종에는 많은 GNU 장점과 힘이 있습니다.
— Peter Tillemans

BusyBox awk에서도 작동합니다.
— MrMas

32

이것은 항상 bash 함수를 만들기 위해 필요한 것입니다. 글렌 잭맨의 답변을 기반으로합니다.

정의

이것을 .bash_profile 등에 추가하십시오.

function regex { gawk 'match($0,/'$1'/, ary) {print ary['${2:-'0'}']}'; }

용법

파일의 각 줄에 대한 정규식 캡처

$ cat filename | regex '.*'

파일의 각 줄에 대한 첫 번째 정규식 캡처 그룹 캡처

$ cat filename | regex '(.*)' 1

2
사용하는 것과 어떻게 grep -o다릅니 까?
— bfontaine

@bfontaine grep -o캡처 한 그룹을 출력 할 수 있습니까?
— Olle Härstedt

1
@ OlleHärstedt 아니요. 캡처 그룹이없는 경우 유스 케이스 만 다룹니다. 이 경우 체인으로 추악해진다 grep -o.
— bfontaine

15

GNU awk를 사용할 수 있습니다 :

$ cat hta
RewriteCond %{HTTP_HOST} !^www\.mysite\.net$
RewriteRule (.*) http://www.mysite.net/$1 [R=301,L]

$ gawk 'match($0, /.*(http.*?)\$/, m) { print m[1]; }' < hta
http://www.mysite.net/

12
+1. 또한, awk와 함께 :awk 'match($0, /.*(http.*?)\$/) { print substr($0,RSTART,RLENGTH) }'
— Ed Morton


1
에드 모튼 (Ed Morton) : 내가 말할 수있는 최상위 수준의 대답이 필요하다. 편집 : uhm ... 그것은 RewriteRule (.*) http://www.mysite.net/$나를 위해 인쇄 됩니다. 하위 그룹 이상입니다.
— rampion


4

확장없이 바닐라 awk에서도 캡처를 시뮬레이션 할 수 있습니다. 직관적이지 않습니다.

단계 1. gensub를 사용하여 문자열에 나타나지 않는 일부 문자와 일치하는 항목을 둘러싸십시오. 단계 2. 문자에 대해 split을 사용하십시오. 단계 3. 분리 된 어레이의 다른 모든 요소는 캡처 그룹입니다.

$ echo 'ab cb ad'| awk '{split (gensub (/ a ./, SUBSEP "&"SUBSEP, "g", $ 0), cap, SUBSEP); 프린트 캡 [2] "|" 캡 [4]; } '
ab | ad

3
나는 거의 확신 gensubA는 gawk특정 기능. awk --version;-?) 를 입력하면 awk에서 무엇을 얻 습니까? 모두에게 행운을 빕니다.
— shellter

6
BusyBox awk도 역시 gensub이 gawk-ism이라고 확신합니다. 이 답변은 gsub를 사용하여 구현할 수도 있습니다.echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
— dubiousjim

3
gensub ()는 gawk 확장이며 gawk의 매뉴얼은 분명히 말합니다. 다른 awk 변형도이를 구현할 수 있지만 여전히 POSIX는 아닙니다. gawk --posix '{gsub (...)}'를 시도하면 불평 할 것입니다
— MestreLion

2
@MestreLion, 당신은 그것이 불만을 의미합니다 gawk --posix '{gensub(...)}'.
— dubiousjim

1
당신이 잘못했다에도 불구하고 POSIX는 AWK 가진 gensub기능을, 당신의 예는 매우 제한 시나리오에 적용 : 전체 패턴이 모두 같은 것을 일치하지 않을 수 있습니다, 그룹화 key=(value)I 만 추출 할 때 value부품.
— Meow

2

Peter Tillemans의 답변을 감싸는 bash 함수를 사용하여 조금 어려움을 겪었지만 여기에 내가 생각해 낸 내용이 있습니다.

정규식 함수 {perl -n -e "/ $ 1 / && printf \"% s \ n \ "," '$ 1'}

"ms"를 인쇄하고 싶지 않기 때문에 다음 정규 표현식 인수에 대해 opsb의 awk 기반 bash 함수보다 더 효과적이라는 것을 알았습니다.

'([0-9]*)ms$'

캡처를 구분하고 그룹을 생략하는 그룹 부분을 볼 수 있기 때문에이 솔루션을 선호합니다. 그러나 누군가 이것이 어떻게 작동하는지 알 수 있습니까? BASH에서이 펄 구문을 제대로 작동시킬 수 없습니다. 왜냐하면 잘 이해하지 못하기 때문입니다. 특히 이중 / 작은 따옴표는$1
— Demis

그것은 이전이나 이후에 한 일이 아니지만, 무엇을하고 있는지 되돌아 보는 것은 두 문자열을 연결하는 것입니다. 첫 번째 문자열은 큰 따옴표로 묶고 (이 첫 번째 문자열에는 백 슬래시로 이스케이프 된 포함 된 큰 따옴표가 포함되어 있음) 두 번째 문자열은 작은 따옴표로 묶습니다 . 그런 다음 해당 연결의 결과는 perl -e에 인수로 제공됩니다. 또한 첫 번째 $ 1 (큰 따옴표 안에있는 것)은 함수에 대한 첫 번째 인수로 대체되고 두 번째 $ 1 (작은 따옴표 안에있는 것)은 그대로 유지됩니다. 이 예
— wytten

나는 이제 조금 더 이해가되고있다. 그렇다면 perl 명령에서 정규식 일치 / 그룹 캡처 정의는 어디에 있습니까? 나는 당신이 쓴 것을 보았습니다 '([0-9]*)ms$'-인수로 제공됩니까 (그리고 문자열은 다른 인수입니까)? 그리고의 출력은 perl -ebash의 printf명령 에 삽입되고 , 대체하기 위해 %s맞습니까? 고마워, 나는 이것을 사용하기를 바라고있다.
— Demis

1
정규 표현식을 작은 따옴표로 묶어 정규 표현식 bash 함수에 대한 유일한 인수로 전달합니다. 예
— wytten December
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.