web-dev-qa-db-fra.com

grep pour "terme" et exclure "un autre terme"

J'essaie de construire une recherche grep qui recherche un terme mais exclut les lignes qui ont un second terme. Je voulais utiliser plusieurs options -e "pattern" mais cela n'a pas fonctionné.

Voici un exemple de commande que j'ai essayée et le message d'erreur généré.

grep -i -E "search term" -ev "exclude term"
grep: exclude term: No such file or directory

Il me semble que le -v s'applique à tous les termes/modèles de recherche. Comme cela fonctionne mais n'inclut pas search term dans les résultats.

grep -i -E "search term" -ve "exclude term"
26
nelaaro

Pour et expressions avec grep, vous avez besoin de deux invocations:

grep -Ei "search term" | grep -Eiv "exclude term"

Si les termes que vous recherchez ne sont pas des expressions régulières, utilisez une correspondance de chaîne fixe (-F) qui est plus rapide:

grep -F "search term" | grep -Fv "exclude term"
39
Thor

À moins d’appeler grep à deux reprises, il n’ya qu’une façon d’y parvenir. Cela implique des expressions régulières compatibles avec Perl (PCRE) et des assertions plutôt approximatives .

Pour rechercher foo à l'exception des correspondances contenant bar , vous pouvez utiliser:

grep -P '(?=^((?!bar).)*$)foo'

Voici comment ça fonctionne:

  • (?!bar) correspond à tout ce qui n'est pas bar sans utiliser les caractères de la chaîne. Alors . consomme un seul caractère.

  • ^((?!bar).)* répète ce qui précède depuis le début de la chaîne (^) jusqu'à la fin de celle-ci ($). Il échouera si bar est rencontré à un moment donné, puisque (?!bar) ne correspondra pas.

  • (?=^((?!bar).)*$) s'assure que la chaîne correspond au modèle précédent, sans utiliser les caractères de la chaîne.

  • foo cherche foo comme d'habitude.

J'ai trouvé ce hack dans Une expression régulière pour faire correspondre une chaîne ne contenant pas un mot? . Dans la réponse de de Bart Kiers , vous pouvez trouver une explication beaucoup plus détaillée du fonctionnement de la prévision négative.

14
Dennis

Si vous voulez faire cela en un seul passage, vous pouvez utiliser awk au lieu de grep.

Format:

echo "some text" | awk '/pattern to match/ && !/pattern to exclude/'

Exemples:

  • echo "hello there" | awk '/hello/ && !/there/'

Ne renvoie rien.

  • echo "hello thre" | awk '/hello/ && !/there/'

Retours: bonjour thre

  • echo "hllo there" | awk '/hello/ && !/there/'

Ne renvoie rien.

Pour plusieurs modèles, vous pouvez utiliser des parenthèses pour les regrouper.

Exemples:

  • echo "hello thre" | awk '(/hello/ || /hi/) && !/there/'

Retours: bonjour thre

  • echo "hi thre" | awk '(/hello/ || /hi/) && !/there/'

Retours: salut trois

  • echo "hello there" | awk '(/hello/ || /hi/) && !/there/'

Ne renvoie rien.

  • echo "hi there" | awk '(/hello/ || /hi/) && !/there/'

Ne renvoie rien.

10
Philip Reese

D'après mes expériences, il ne semble pas que cela fasse beaucoup de différence si vous dirigez vos termes exclus par grep ou sed. Sed possède d'autres fonctionnalités utiles de remplacement de texte que j'utilise souvent pour mieux filtrer la sortie des fichiers journaux. Je vais donc utiliser sed car je combine pas mal de filtres sur sed.

 wc /var/log/Tomcat/tomcat.2013-01-14.log.1 
 1851725 
 
/usr/bin/time grep -i - E "(loginmanager)" /var/log/Tomcat/tomcat.2013-01-14.log.1 | sed -e "/ login OK/d" -e "/ Connexion expirée/d" | wc 
 24.05utilisateur 0.15système 0: 25.27effondré à 95% de l'UC (0avgtext + 0avgdata 3504maxresident) k 
 0sortie + 0 sorties (0major + 246minor) pagefaults 0swaps 
. .] 
/usr/bin/time grep -i -E "(loginmanager)" /var/log/Tomcat/tomcat.2013-01-14.log.1 | sed -e "/ login OK/d" -e "/ Connexion expirée/d" | wc 
 23.50user 0.16système 0: 24.48effondré à 96% de l'UC (0avgtext + 0avgdata 3504maxresident) k 
 0puts + 0outputs (0major + 246minor) pagefaults 0swaps 
. .] 
/usr/bin/time grep -i -E "(loginmanager)" /var/log/Tomcat/tomcat.2013-01-14.log.1 | grep -v -e "login OK" -e "Login expiré" | wc 
 23.08user 0.14system 0: 23.55effondrer à 98% du CPU (0avgtext + 0avgdata 3504maxresident) k 
 0puts + 0outputs (0major + 246minor) pagefaults 0swaps 
. .] 
/usr/bin/time grep -i -E "(loginmanager)" /var/log/Tomcat/tomcat.2013-01-14.log.1 | grep -v -e "login OK" -e "Login expiré" | wc 
 23.50user 0.15système 0: 25.27a échoué à 93% de l'UC (0avgtext + 0avgdata 3488maxresident) k 
 0puts + 0putputs (0major + 245minor) pagefaults 0swaps 
. .] 
1
nelaaro