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.