Grep regex ne contenant PAS de chaîne

187

Je passe une liste de modèles de regex à greppour vérifier par rapport à un fichier syslog. Ils correspondent généralement à une adresse IP et à une entrée de journal;

grep "1\.2\.3\.4.*Has exploded" syslog.log

C'est juste une liste de motifs comme la "1\.2\.3\.4.*Has exploded"partie que je passe, dans une boucle, donc je ne peux pas passer "-v" par exemple.

Je suis confus en essayant de faire l'inverse de ce qui précède, et de NE PAS faire correspondre les lignes avec une certaine adresse IP et une certaine erreur, donc "! 1.2.3.4. * A explosé" correspondra aux lignes syslog pour autre chose que 1.2.3.4 m'indiquant qu'il a explosé . Je dois pouvoir inclure une adresse IP pour ne PAS correspondre.

J'ai vu divers articles similaires sur StackOverflow. Cependant, ils utilisent des modèles de regex avec lesquels je n'arrive pas à travailler grep. Quelqu'un peut-il fournir un exemple de travail pour greps'il vous plaît?

MISE À JOUR: Cela se produit dans un script comme celui-ci;

patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
do
 grep "${patterns[$i]}" logfile.log
done
jwbensley
la source
Voulez-vous dire que vous voulez parfois faire correspondre un modèle, mais d'autres fois que vous voulez tout faire correspondre sauf un certain modèle? (cela semble être une exigence étrange, mais peu importe). Dans ce cas, pourquoi ne pas parcourir deux listes de modèles différentes?
beerbajay
Eh bien, je ne connais pas très bien les regex; Je ne veux pas grep pour "Has Exploded" parce que je ne veux pas savoir ceci à propos de chaque périphérique de journalisation, puis-je en quelque sorte grep pour "Has Exploded" et! 9.10.11.12 dans une seule instruction?
jwbensley
Si vous devez absolument le faire en une seule déclaration, les regards négatifs sont la voie à suivre, comme le suggère Neil. Voir mon commentaire ici.
beerbajay
Utilisez la correspondance d'expression régulière de style PCRE et une assertion d'anticipation négative, conformément à la réponse de @Neil: les patterns[3]="\!9\.10\.11\.12.*Has exploded"modifications patterns[3]="(?<!9\.10\.11\.12).*Has exploded"et les grep "${patterns[$i]}" logfile.logmodifications apportées à grep -P "${patterns[$i]}" logfile.logPCRE supposent plus de métacaractères par défaut, de sorte que certains des échappements doivent être supprimés d'autres expressions correspondantes.
Codex24

Réponses:

355

grepcorrespond, grep -vfait l'inverse. Si vous devez "faire correspondre A mais pas B", vous utilisez généralement des tubes:

grep "${PATT}" file | grep -v "${NOTPATT}"
bièrebajay
la source
Ceci entre au milieu d'une boucle comme je l'ai mentionné et je passe juste le PATTERN à grep donc je ne peux pas utiliser "-v" comme je l'ai mentionné. Je fais juste une boucle autour d'une liste de PATTERNs et je passe à grep.
jwbensley
1
Vous pouvez en effet l'utiliser -vet vous pouvez l'utiliser en boucle. Vous devez peut-être être plus précis sur vos limites, ou peut-être avez-vous une idée fausse sur la façon dont votre script devrait fonctionner. Essayez de publier du code.
beerbajay
Merci beerbajay, j'ai ajouté un code extrait à l'article original pour donner un peu de contexte. Voyez-vous ce que je veux dire maintenant?
jwbensley
Cette réponse n'est pas tout à fait correcte mais vous étiez à peu près en train d'écrire beerbajay, j'avais besoin de repenser la boucle et d'utiliser -v à la fin. Merci pour le pointeur;)
jwbensley
1
Mais que se passe-t-il si A est composé de B? En d'autres termes, que faire si je veux faire correspondre des lignes sans A et des lignes avec AB? Un tuyau ne fonctionnera pas.
pawamoy
16
(?<!1\.2\.3\.4).*Has exploded

Vous devez exécuter ceci avec -P pour avoir une recherche négative (expression régulière Perl), donc la commande est:

grep -P '(?<!1\.2\.3\.4).*Has exploded' test.log

Essaye ça. Il utilise la recherche négative en arrière pour ignorer la ligne si elle est précédée de 1.2.3.4. J'espère que ça t'as aidé!

Neil
la source
1
Je suis presque sûr que grepcela ne prend pas en charge le lookaround. Sauf si vous utilisez Gnu grepet utilisez le --Pparamètre pour lui faire utiliser un moteur PCRE.
Tim Pietzcker
Non, grep ne prend pas en charge ce type de regex; $ grep -P (? <\! 1 \ .2 \ .3 \ .4) test.log -bash: erreur de syntaxe près du jeton inattendu `('
jwbensley
Vous allez devoir citer l'expression régulière si elle contient des caractères qui seraient interprétés par le shell.
beerbajay
citation correcte: grep -P '(?<!1\.2\.3\.4) Has exploded' test.lognotez que le lookbehind ne fonctionne que sur les caractères précédant immédiatement la partie correspondante de l'expression, donc s'il y a d'autres choses entre l'adresse et le message, par exemple 1.2.3.4 FOO Has exploded, cela ne fonctionnera pas.
beerbajay
@TimPietzcker, très observateur. J'ajouterai cela à la question. Aussi, veuillez noter qu'il y a un .*après le regard négatif puisque son exemple l'a également, j'imagine qu'il pourrait y avoir un autre texte entre les deux.
Neil
2
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
 do
grep "${patterns[$i]}" logfile.log
done

devrait être le même que

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
Krecker
la source