web-dev-qa-db-fra.com

Regex lookahead pour 'pas suivi de' dans grep

Je tente de grep pour toutes les instances de Ui\. non suivies de Line ou même de la lettre L

Quelle est la bonne façon d'écrire une expression rationnelle pour trouver toutes les occurrences d'une chaîne particulière NON suivie d'une autre chaîne?

Utilisation de lookaheads

grep "Ui\.(?!L)" *
bash: !L: event not found


grep "Ui\.(?!(Line))" *
nothing
84
Lee Quarella

Le résultat négatif que vous recherchez nécessite un outil plus puissant que la variable standard grep. Vous avez besoin d'un grep activé pour PCRE.

Si vous avez GNU grep, la version actuelle prend en charge les options -P ou --Perl-regexp et vous pouvez ensuite utiliser l'expression régulière souhaitée.

Si vous n'avez pas (une version suffisamment récente de) GNU grep, envisagez alors d'obtenir ack .

123
Jonathan Leffler

La réponse à une partie de votre problème est ici, et ack se comporterait de la même manière: Ack & lookahead négatif donnant des erreurs

Vous utilisez des guillemets doubles pour grep, ce qui permet à bash "d'interpréter ! en tant que commande d'extension de l'historique".

Vous devez envelopper votre modèle dans SINGLE-CITES: grep 'Ui\.(?!L)' *

Cependant, voir la réponse de @ JonathanLeffler pour résoudre les problèmes liés à des aspects négatifs dans la variable grep!

33
NHDaly

Vous ne pouvez probablement pas effectuer d’observations négatives standard avec grep, mais vous devriez normalement pouvoir obtenir un comportement équivalent en utilisant le commutateur "inverse" -v '. En utilisant cela, vous pouvez construire une regex pour le complément de ce que vous voulez faire correspondre et ensuite la diriger vers 2 greps.

Pour la regex en question, vous pourriez faire quelque chose comme:

grep 'Ui\.' * | grep -v 'Ui\.L'
8
Karel Tucek

Si votre grep ne prend pas en charge -P ou --Perl-regexp, vous pouvez installer grep, par exemple, compatible PCRE. "pcregrep", alors qu'il n'aura pas besoin d'options de ligne de commande comme GNU grep pour accepter les expressions régulières compatibles Perl, il suffit de lancer 

pcregrep "Ui\.(?!Line)"

Vous n'avez pas besoin d'un autre groupe imbriqué pour "Ligne", comme dans votre exemple "Ui. (?! (Ligne))" - le groupe extérieur suffit, comme je l'ai montré ci-dessus.

Permettez-moi de vous donner un autre exemple d'assertions négatives: lorsque vous avez une liste de lignes, renvoyée par "ipset", chaque ligne indiquant le nombre de paquets au milieu de la ligne, et vous n'avez pas besoin de lignes avec zéro paquet, vous courir:

ipset list | pcregrep "packets(?! 0 )"

Si vous aimez les expressions régulières compatibles Perl et que vous avez Perl mais que vous n'avez pas pcregrep ou que votre grep ne prend pas en charge --Perl-regexp, vous pouvez utiliser des scripts Perl d'une ligne qui fonctionnent de la même manière que grep:

Perl -e "while (<>) {if (/Ui\.(?!Lines)/){print;};}"

Perl accepte stdin de la même manière que grep, par exemple.

ipset list | Perl -e "while (<>) {if (/packets(?! 0 )/){print;};}"
0
Maxim Masiutin