4
votes

Grep - comment afficher uniquement le contenu d'un groupe de capture

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!


2 commentaires

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 par sed ... donc, si vous avez besoin de manipuler des groupes de capture, sed serait un meilleur choix


Le 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?


5 Réponses :


2
votes

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 )"


4 commentaires

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.



1
votes

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


3 commentaires

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 ...



1
votes

Juste une version awk .

awk -F, '/hello[0-9]+, please match me/ {print $1}' file
hello1


0 commentaires

2
votes

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 .


4 commentaires

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.



1
votes

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.


0 commentaires