Parfois (dans des cas simples), il est possible d'ajuster le séparateur de champ ( FS) et de choisir ce que l'on souhaite faire correspondre avec a $field. Le pré-formatage de l'entrée peut également aider.
Apparemment, quelqu'un n'est pas d'accord. Cette page Web date de 2005: tek-tips.com/faqs.cfm?fid=5674 Elle confirme que vous ne pouvez pas réutiliser les groupes correspondants dans awk.
Peter Tillemans
3
Je préfère 'perl -n -p -e ...' à awk pour presque tous les cas d'utilisation, car il est plus flexible, plus puissant et a une syntaxe plus saine à mon avis.
Peter Tillemans
15
gawk! = awk. Ce sont des outils différents et gawkne sont pas disponibles par défaut dans la plupart des endroits.
Oli
6
L'OP a spécifiquement demandé une solution awk, donc je ne pense pas que ce soit une réponse.
Joppe
6
@Joppe, vous ne pouvez pas donner une solution awk s'il n'y a pas de solution. À la ligne 3, j'explique qu'AWK ne prend pas en charge la capture de groupes et j'ai donné une alternative, que le PO a apparemment appréciée parce que cette réponse a été acceptée. Comment pourrais-je mieux répondre à cette question?
Peter Tillemans
335
Avec gawk, vous pouvez utiliser la matchfonction 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.
En quoi est-ce différent de l'utilisation grep -o?
bfontaine
@bfontaine Pourrait grep -oproduire des groupes capturés?
Olle Härstedt
1
@ OlleHärstedt Non, cela n'a pas pu. Il ne couvre votre cas d'utilisation que si vous n'avez pas de groupes de capture. Dans ce cas, ça devient moche avec les enchaînés grep -o.
Ed Morton: cela mérite une réponse de haut niveau, je dirais. edit: uhm ... qui imprime RewriteRule (.*) http://www.mysite.net/$pour moi, ce qui est plus que le sous-groupe.
Vous pouvez également simuler la capture dans awk vanilla, sans extensions. Ce n'est pas intuitif cependant:
étape 1. utilisez gensub pour entourer les correspondances avec un caractère qui n'apparaît pas dans votre chaîne. étape 2. Utilisez la division contre le personnage. étape 3. Chaque autre élément du tableau divisé est votre groupe de capture.
Je suis presque certain que gensubc'est une gawkfonction spécifique. Qu'obtenez-vous de votre awk si vous tapez awk --version; -?). Bonne chance à tous.
shellter
6
Je suis absolument certain que gensub est un gawk-ism, bien que BusyBox awk l'ait également. Cette réponse pourrait également ê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]}'
dubiousjim
3
gensub () est une extension gawk, le manuel de gawk le dit clairement. D'autres variantes awk peuvent également l'implémenter, mais ce n'est toujours pas POSIX. Essayez gawk --posix '{gsub (...)}' et il se plaindra
MestreLion
2
@MestreLion, vous voulez dire qu'il se plaindra gawk --posix '{gensub(...)}'.
dubiousjim
1
Même si vous aviez tort à propos de POSIX awk ayant la gensubfonction, votre exemple s'applique à un scénario très limité: le motif entier est groupé, il ne peut pas correspondre à quelque chose comme tout key=(value)quand je veux extraire uniquement les valueparties.
Meow
2
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 trouvé:
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 d'opsb pour l'argument d'expression régulière suivant, car je ne veux pas que le "ms" soit imprimé.
Je préfère cette solution, car vous pouvez voir les parties du groupe qui délimitent la capture, tout en les omettant. Cependant, quelqu'un pourrait-il expliquer comment cela fonctionne? Je ne peux pas faire fonctionner correctement cette syntaxe perl dans BASH, car je ne la comprends pas très bien - en particulier les guillemets doubles / simples autour$1
Demis
Ce n'est pas quelque chose que j'ai fait avant ou depuis, mais regarder en arrière ce qu'il fait revient à concaténer deux chaînes, la première chaîne étant entre guillemets doubles (cette première chaîne contient des guillemets doubles intégrés échappés avec barre oblique inverse) et la deuxième chaîne étant entre guillemets simples . Ensuite, le résultat de cette concaténation est fourni comme argument à perl -e. Vous devez également savoir que le premier $ 1 (celui entre guillemets doubles) est remplacé par le premier argument de la fonction, tandis que le deuxième $ 1 (celui entre guillemets simples) reste intact. Voir cet exemple
wytten
Je vois, c'est un peu plus logique maintenant. Alors, où dans la commande perl se trouve la définition de capture de correspondance / groupe regex? Je vois que vous avez écrit '([0-9]*)ms$'- est-ce fourni comme argument (et la chaîne un autre argument)? Et la sortie de perl -eest insérée dans la printfcommande de bash alors, pour remplacer %s, est-ce vrai? Merci, j'espère l'utiliser.
Demis
1
Vous passez une expression régulière entre guillemets simples comme seul argument de la fonction basge regex. Exemple
FS
) et de choisir ce que l'on souhaite faire correspondre avec a$field
. Le pré-formatage de l'entrée peut également aider.gawk
(puisqu'il utilisegensub
).Réponses:
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 AWK ne capture pas ses groupes.
vous pourriez envisager d'utiliser quelque chose comme:
le drapeau -n fait que perl boucle sur chaque ligne comme le fait awk.
la source
gawk
! =awk
. Ce sont des outils différents etgawk
ne sont pas disponibles par défaut dans la plupart des endroits.Avec gawk, vous pouvez utiliser la
match
fonction pour capturer des groupes entre parenthèses.exemple:
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()
etsubstr
.exemple:
sorties
cd
.la source
C'est quelque chose dont j'ai besoin tout le temps, j'ai donc créé une fonction bash pour cela. C'est basé sur la réponse de Glenn Jackman.
Définition
Ajoutez ceci à votre .bash_profile etc.
Usage
Capturer l'expression régulière pour chaque ligne du fichier
Capturez le premier groupe de capture regex pour chaque ligne du fichier
la source
grep -o
?grep -o
produire des groupes capturés?grep -o
.Vous pouvez utiliser GNU awk:
la source
awk 'match($0, /.*(http.*?)\$/) { print substr($0,RSTART,RLENGTH) }'
RewriteRule (.*) http://www.mysite.net/$
pour moi, ce qui est plus que le sous-groupe.RSTART
et seRLENGTH
réfère à la sous-chaîne correspondant au motifVous pouvez également simuler la capture dans awk vanilla, sans extensions. Ce n'est pas intuitif cependant:
étape 1. utilisez gensub pour entourer les correspondances avec un caractère qui n'apparaît pas dans votre chaîne. étape 2. Utilisez la division contre le personnage. étape 3. Chaque autre élément du tableau divisé est votre groupe de capture.
la source
gensub
c'est unegawk
fonction spécifique. Qu'obtenez-vous de votre awk si vous tapezawk --version
; -?). Bonne chance à tous.echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
gawk --posix '{gensub(...)}'
.gensub
fonction, votre exemple s'applique à un scénario très limité: le motif entier est groupé, il ne peut pas correspondre à quelque chose comme toutkey=(value)
quand je veux extraire uniquement lesvalue
parties.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 trouvé:
J'ai trouvé que cela fonctionnait mieux que la fonction bash basée sur awk d'opsb pour l'argument d'expression régulière suivant, car je ne veux pas que le "ms" soit imprimé.
la source
$1
'([0-9]*)ms$'
- est-ce fourni comme argument (et la chaîne un autre argument)? Et la sortie deperl -e
est insérée dans laprintf
commande de bash alors, pour remplacer%s
, est-ce vrai? Merci, j'espère l'utiliser.