J'essaye de trouver un moyen pour grep de sortir uniquement le contenu d'un groupe de capture. Par exemple, si j'ai le fichier suivant:
grep -Eo '(hello[0-9]+), please match me' file
Je voudrais
hello1, please match me hello2, please do not match me
Pour sortir hello1
. Cependant, il produit hello1, please match me
.
Maintenant, je sais que grep -Po 'hello[0-9]+(?=, please match me)'
fera l'affaire, mais je pense qu'il doit y avoir un moyen de simplement renvoyer un groupe de capture, mais je n'ai pas pu 'ne trouve aucune info (sur le net et dans man grep
).
Est-ce possible, ou les groupes de capture sont-ils uniquement destinés à être référencés en arrière? Cela me semblerait étrange s'il n'y avait aucun moyen de faire ça.
Merci pour votre temps et n'hésitez pas à critiquer la façon dont ce message est construit!
5 Réponses :
Cette question a été posée il y a dix ans , je ne la marquerai donc pas comme un double. J'ai également remarqué qu'aucune solution sed n'avait été donnée puisque OP a demandé une réponse sans:
sed -nr 's/(hello[0-9]+), please match me/\1/p' test.txt
-n
signifie calme (n'imprimera rien sauf si demandé explicitement)-r
permet d'utiliser des expressions régulières étendues (évite ici d'utiliser \
avant les parenthèses)s/reg/repl/p
signifie "si regexp reg
correspond à la ligne courante, remplacez-la par le texte capturé par repl
et l’imprime ( /p
)"Alors oui, il semblerait que ce soit impossible de faire ça en grep? Votre solution semble être la meilleure. J'attendrai de voir si quelqu'un nous prouve le contraire, mais sinon, je mettrai votre commentaire comme solution.
La boucle est maintenant bouclée, puisque g/re/p
signifie "rechercher globalement une expression régulière et imprimer"
@Amessihel c'est vrai! J'ai des doutes sur celui qui accepte cependant, car la réponse de Rici est bonne aussi
@Amessihel, je vais choisir la réponse de Rici parce qu'elle est la plus proche de ce que j'ai demandé. Votre réponse est très bonne aussi, merci.
Il existe un moyen délicat avec le mode Perl
$ echo hello1, please match me | rev | grep -oP "$(echo hello1K\\, please match me | rev)" | rev
essentiellement en utilisant \K
lookbehind en inversant les termes d'entrée et de recherche.
Vous pouvez également externaliser l'inversion du terme de recherche vers rev
.
$ echo "hello1, please match me" | rev | grep -oP 'em hctam esaelp ,\K[0-9]olleh' | rev hello1
Quel est l'avantage de cette solution puisque OP a demandé un moyen simple de renvoyer un groupe capturé?
@Amessihel Cela ne répond pas vraiment à mes exigences, bien sûr, mais je trouve que c'est une solution vraiment amusante
regarder en arrière est plus facile que regarder en avant, c'est probablement pourquoi il y a un \K
mais pas un pour regarder en avant. Pas vraiment pour une utilisation pratique ...
Juste une version awk
.
awk -F, '/hello[0-9]+, please match me/ {print $1}' file hello1
Si vous avez pcregrep
ou pcre2grep
vous pouvez utiliser l' -o1
de ligne de commande -o1
pour demander que seul le groupe de capture 1 soit pcregrep
. (Ou remplacez 1 par un autre nombre s'il y a plus de captures dans l'expression régulière.)
Vous pouvez utiliser la commande -o N
plusieurs fois si vous souhaitez générer plus d'un groupe de capture.
Autant que je sache, grep -P
pas cette extension. Vous trouverez pcre2grep
dans le paquet Debian / Ubuntu pcre2-utils
. pcregrep
est dans le package pcregrep
.
Pourquoi apt
ne trouve-t-il pas PCRE2 comme pcre2grep
sur Ubuntu 19.04? $ sudo apt-get install pcre2grep; Reading package lists... Done; Building dependency tree; Reading state information... Done; E: Unable to locate package pcre2grep
@vstepaniuk: Comme je l'ai dit ci-dessus, "Vous trouverez pcre2grep dans le paquet Debian / Ubuntu pcre2-utils ."
Pourquoi apt ne trouve- t- il pas PCRE2 comme pcre2grep sur Ubuntu 19.04?
@vstepaniuk: parce que celui qui a construit le paquet contenant divers utilitaires utilisant libpcre2 a choisi de ne pas construire un paquet séparé contenant uniquement pcre2grep. Je n'ai aucune idée de ce qui a motivé cette décision. Il faudrait leur demander. Mais apt
ne connaît que les noms de paquet.
grep
, sed
et awk
ont d'anciens moteurs d'expression régulière qui ne prennent en charge aucune fonctionnalité regex moderne. Je ne pense plus vraiment qu'ils soient adaptés à leur objectif.
Une chose pour laquelle Perl
est toujours bon est de remplacer ceux de quasiment tous les one-liners, car il a un très beau moteur regex moderne et quelques commutateurs de ligne de commande pratiques, -ne
et -pe
.
Les commutateurs font que Perl applique automatiquement votre expression à chaque ligne de l'entrée et soit imprime inconditionnellement le résultat, soit vous permet de contrôler l'impression du résultat.
Par exemple, pour imprimer le premier hello
suivi d'un chiffre ( hello\d
) pour toutes les lignes qui ont hello\d
suivi de please match me
, vous pouvez faire:
perl -ne 'm/(hello\d) please match me/ && print "$1\n"' <file>
Il existe de nombreux sites intéressants qui répertorient les tâches courantes que vous pouvez effectuer avec un one-liner Perl, comme celui-ci .
Je pense aussi que ripgrep devrait être dans la boîte à outils de tout le monde.
pour autant que je sache,
GNU grep
ne prend pas en charge l'obtention uniquement des groupes capturés, sauf si vous utilisez des lookarounds avec l'option PCRE ...ripgrep
(une implémentation alternative) prend en charge ce que vous demandez, mais dans l'esprit cela ressemble plus à la recherche et la fonctionnalité de remplacement fournie parsed
... donc, si vous avez besoin de manipuler des groupes de capture,sed
serait un meilleur choixLe groupe non consommateur
(?=)
Avec-P
permet une sorte de fonction AND dans les expressions rationnelles. L'autre façon de ET vos regex avec grep est de rediriger grep vers grep. Alors, quel est le problème avec le piping grep vers grep ici?