275 votes

AWK : Accès au groupe capturé à partir d'un motif de ligne

Si j'ai une commande awk

pattern { ... }

et le motif utilise un groupe de capture, comment puis-je accéder à la chaîne ainsi capturée dans le bloc ?

3 votes

0 votes

Parfois (dans des cas simples), il est possible d'ajuster le séparateur de champs ( FS ) et choisir ce que l'on souhaite assortir d'une $field . Le préformatage de l'entrée pourrait également être utile.

1 votes

Il existe un meilleure réponse sur la question de la duplication.

401voto

glenn jackman Points 69748

Avec gawk, vous pouvez utiliser le match pour capturer les groupes entre parenthèses.

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

exemple :

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

sorties cd .

Notez l'utilisation spécifique de gawk qui implémente la fonctionnalité en question.

Pour une alternative portable, vous pouvez obtenir des résultats similaires avec match() y substr .

exemple :

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

sorties cd .

4 votes

Oui, les variantes gxxx ont beaucoup d'avantages et de puissance GNU supplémentaires.

1 votes

Fonctionne également dans BusyBox awk.

210voto

Peter Tillemans Points 20129

C'était une promenade dans le passé...

J'ai remplacé awk par perl il y a longtemps.

Apparemment, le moteur d'expression régulière de AWK ne capture pas ses groupes.

vous pouvez envisager d'utiliser quelque chose comme :

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

l'option -n permet à perl de boucler sur chaque ligne comme le fait awk.

4 votes

Apparemment, quelqu'un n'est pas d'accord. Cette page Web date de 2005 : tek-tips.com/faqs.cfm?fid=5674 Cela confirme que vous ne pouvez pas réutiliser les groupes appariés en awk.

0 votes

cet article semble aussi être d'accord avec vous.

1 votes

Comme l'indique l'article de tek-tips, gawk peut réutiliser les groupes de capture.

36voto

opsb Points 6860

C'est quelque chose dont j'ai besoin tout le temps, alors j'ai créé une fonction bash pour cela. Elle est basée sur la réponse de Glenn Jackman.

Définition

Ajoutez ceci à votre .bash_profile, etc.

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

Utilisation

Capture de la regex pour chaque ligne du fichier

$ cat filename | regex '.*'

Capture du 1er groupe de capture regex pour chaque ligne du fichier

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

2 votes

Quelle est la différence avec l'utilisation de grep -o ?

0 votes

@bfontaine pourrait grep -o les groupes capturés en sortie ?

2 votes

@OlleHärstedt Non, ça ne pourrait pas. Cela ne couvre que votre cas d'utilisation lorsque vous n'avez pas de groupes de capture. Dans ce cas, les choses se gâtent avec les groupes de capture chaînés. grep -o 's.

19voto

Derecho Points 1122

Vous pouvez utiliser 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/

5 votes

1 votes

Ed Morton : cela mérite une réponse de haut niveau je dirais. edit : uhm... cela imprime RewriteRule (.*) http://www.mysite.net/$ pour moi, ce qui est plus que le sous-groupe.

6voto

ydrol Points 41

Vous pouvez également simuler la capture dans l'awk vanilla, sans extensions. Mais ce n'est pas intuitif :

étape 1 : utilisez gensub pour entourer les correspondances d'un caractère qui n'apparaît pas dans votre chaîne. étape 2. Utilisez split contre le caractère. étape 3. Chaque autre élément du tableau divisé est votre groupe de capture.

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

4 votes

Je suis presque certain que gensub est un gawk fonction spécifique. Qu'obtenez-vous de votre awk si vous tapez awk --version ;- ?). Bonne chance à tous.

7 votes

Je suis tout à fait certain que gensub est un gawk-ism, bien que BusyBox awk l'ait aussi. Cette réponse pourrait aussi être implémentée en utilisant gsub, cependant : echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'

4 votes

Gensub() est une extension de gawk, le manuel de gawk le dit clairement. D'autres variantes d'awk peuvent également l'implémenter, mais ce n'est toujours pas POSIX. Essayez gawk --posix '{gsub(...)}' et il se plaindra de ce qui suit

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X