web-dev-qa-db-fra.com

AWK: Accéder au groupe capturé à partir du motif de ligne

Si j'ai une commande awk

pattern { ... }

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

207
rampion

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

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

Apparemment, le moteur des expressions régulières AWK ne capture pas ses groupes.

vous pourriez envisager d'utiliser quelque chose comme:

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

l'indicateur -n force Perl à boucler chaque ligne comme le fait awk.

150
Peter Tillemans

Avec gawk, vous pouvez utiliser la fonction match pour capturer des 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() et substr.

exemple:

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

sorties cd.

301
glenn jackman

C'est quelque chose dont j'ai besoin tout le temps, alors j'ai créé une fonction bash pour cela. C'est basé 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'}']}'; }

Usage

Capturer une expression rationnelle pour chaque ligne du fichier

$ cat filename | regex '.*'

Capturer le groupe de capture du 1er regex pour chaque ligne du fichier

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

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/
12
Dan Ellis

Vous pouvez également simuler la capture dans Vanilla awk, sans extensions. Ce n'est pas intuitif si:

étape 1. utilisez gensub pour entourer les correspondances avec des caractères qui n'apparaissent pas dans votre chaîne. étape 2. Utilisez diviser contre le personnage. étape 3. Tous les autres éléments du tableau fractionné constituent votre groupe de capture.

 $ echo 'ab cb ad' | awk '{split (gensub (/ a ./, SUBSEP "&" SUBSEP, "g", 0 $), plafond, SUBSEP); capuchon d'impression [2] "|" capuchon [4]; } '
 ab | ad 
3
ydrol

J'ai eu un peu de mal à trouver une fonction bash qui enveloppe la réponse de Peter Tillemans, mais voici ce que j'ai proposé:

fonction regex {Perl -n -e "/ $ 1/&& printf \"% s\n\"," '$ 1'}

J'ai trouvé que cela fonctionnait mieux que la fonction bash basée sur awk de opsb pour l'argument d'expression régulière suivant, car je ne souhaite pas que le "ms" soit imprimé.

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