À 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 la correspondance de chaîne fixe (-F
) qui est plus rapide :
grep -F "search term" | grep -Fv "exclude term"
À moins d'invoquer grep deux fois, je ne peux penser qu'à une seule façon d'y parvenir. Cela implique des expressions régulières compatibles Perl (PCRE) et des assertions de contournement plutôt hackées.
Pour rechercher foo à l'exclusion des correspondances contenant bar , vous pouvez utiliser :
grep -P '(?=^((?!bar).)*$)foo'
Voici comment cela fonctionne :
-
(?!bar)
correspond à tout ce qui n'est pas barré sans consommer de 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 ($
). Il échouera sibar
est rencontré à un moment donné, depuis(?!bar)
ne correspondra pas. -
(?=^((?!bar).)*$)
s'assure que la chaîne correspond au modèle précédent, sans consommer de caractères de la chaîne. -
foo
recherche foo comme d'habitude.
J'ai trouvé ce hack dans Expression régulière pour faire correspondre une chaîne ne contenant pas de mot ?. Dans la réponse de Bart Kiers, vous pouvez trouver une explication beaucoup plus détaillée du fonctionnement de l'anticipation négative.
Si vous voulez le faire en une seule passe, 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 à vous trois
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 à vous trois
echo "hi thre" | awk '(/hello/ || /hi/) && !/there/'
Retours :bonjour
echo "hello there" | awk '(/hello/ || /hi/) && !/there/'
Ne renvoie rien.
echo "hi there" | awk '(/hello/ || /hi/) && !/there/'
Ne renvoie rien.