J'essaie de grep pour toutes les instances de Ui\.
non suivies Line
ou même simplement de la lettreL
Quelle est la bonne façon d'écrire une expression régulière pour trouver toutes les instances d'une chaîne particulière NON suivie d'une autre chaîne?
Utiliser des lookaheads
grep "Ui\.(?!L)" *
bash: !L: event not found
grep "Ui\.(?!(Line))" *
nothing
regex
grep
regex-lookarounds
Lee Quarella
la source
la source
set +o histexpand
dans Bash ouset +H
, YMMV.Réponses:
La recherche négative, ce que vous recherchez, nécessite un outil plus puissant que la norme
grep
. Vous avez besoin d'un grep compatible PCRE.Si vous avez GNU
grep
, la version actuelle prend en charge les options-P
ou--perl-regexp
et vous pouvez alors utiliser l'expression régulière que vous souhaitez.Si vous n'avez pas (une version suffisamment récente de) GNU
grep
, envisagez de vous procurerack
.la source
!
comme un caractère spécial.-P
ne sont pas pris en charge résultat de la tuyauterie d'essayer à nouveaugrep --invert-match
, ex:git log --diff-filter=D --summary | grep -E 'delete.*? src' | grep -E --invert-match 'xml'
. Assurez-vous de voter pour la réponse de @Vinicius Ottoni.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
!
comme commande de développement de l'historique».Vous devez envelopper votre modèle de guillemets uniques:
grep 'Ui\.(?!L)' *
Cependant, consultez la réponse de @ JonathanLeffler pour résoudre les problèmes liés aux anticipations négatives en standard
grep
!la source
grep
avec la fonctionnalité de standardgrep
, où le standard pourgrep
est POSIX. Ce que vous dites est également vrai - je lance Bash avec les barbarismes C-shell désactivés (parce que si je voulais un shell C, j'en utiliserais un, mais je n'en veux pas), donc les!
choses ne m'affectent pas - mais pour obtenir des lookaheads négatifs, vous avez besoin de non standardgrep
.Vous ne pouvez probablement pas effectuer de lookaheads négatifs standard en utilisant grep, mais vous devriez généralement 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, puis la diriger à travers 2 greps.
Pour le regex en question, vous pouvez faire quelque chose comme
la source
Si vous avez besoin d'utiliser une implémentation de regex qui ne prend pas en charge les anticipations de recherche négatives et que cela ne vous dérange pas de faire correspondre des caractères supplémentaires *, vous pouvez utiliser des classes de caractères annulés
[^L]
, une alternance|
et la fin de l'ancre de chaîne$
.Dans votre cas
grep 'Ui\.\([^L]\|$\)' *
fait le travail.Ui\.
correspond à la chaîne qui vous intéresse\([^L]\|$\)
correspond à tout caractère unique autre queL
ou correspond à la fin de la ligne:[^L]
ou$
.Si vous souhaitez exclure plus d'un caractère, il vous suffit de lui ajouter plus d'alternance et de négation. Pour trouver
a
non suivi debc
:grep 'a\(\([^b]\|$\)\|\(b\([^c]\|$\)\)\)' *
Qui est soit (
a
suivi de nonb
ou suivi de la fin de la ligne:a
alors[^b]
ou$
) ou (a
suivi deb
qui est soit suivi de non,c
soit suivi de la fin de la ligne:a
alorsb
, alors[^c]
ou$
.Ce type d'expression devient assez lourd et sujet aux erreurs même avec une chaîne courte. Vous pouvez écrire quelque chose pour générer les expressions à votre place, mais il serait probablement plus facile d'utiliser simplement une implémentation de regex qui prend en charge les anticipations négatives.
* Si votre implémentation prend en charge les groupes sans capture, vous pouvez éviter de capturer des caractères supplémentaires.
la source
Si votre grep ne prend pas en charge -P ou --perl-regexp, et que vous pouvez installer un grep compatible PCRE, par exemple "pcregrep", il n'aura pas besoin d'options de ligne de commande comme GNU grep pour accepter le standard compatible Perl expressions, vous venez de courir
Vous n'avez pas besoin d'un autre groupe imbriqué pour "Line" comme dans votre exemple "Ui. (?! (Line))" - le groupe externe est suffisant, comme je l'ai montré ci-dessus.
Permettez-moi de vous donner un autre exemple de recherche 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 que vous n'avez pas besoin de lignes avec zéro paquet, vous courir:
Si vous aimez les expressions régulières compatibles avec 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 sur une ligne qui fonctionnent de la même manière que grep:
Perl accepte stdin de la même manière que grep, par exemple
la source