Je voudrais obtenir la correspondance multi-motifs avec AND entre les motifs, cest-à-dire équivalent à exécuter plusieurs greps dans une séquence:
grep pattern1 | grep pattern2 | ...
Alors comment le convertir en quelque chose comme?
grep pattern1 & pattern2 & pattern3
Je voudrais utiliser un seul grep parce que je construis des arguments de manière dynamique, donc tout doit tenir dans une chaîne. Utiliser le filtre est une fonctionnalité système, pas grep, donc ce nest pas un argument pour cela.
Ne confondez pas cette question avec:
grep "pattern1\|pattern2\|..."
Il sagit dune correspondance à plusieurs modèles OU .
Commentaires
Réponse
agrep
peut le faire avec cette syntaxe:
agrep "pattern1;pattern2"
Avec GNU grep
, une fois construit w Avec le support PCRE, vous pouvez faire:
grep -P "^(?=.*pattern1)(?=.*pattern2)"
Avec ast grep
:
grep -X ".*pattern1.*&.*pattern2.*"
(ajout de .*
en tant que <x>&<y>
correspond aux chaînes qui correspondent à la fois à <x>
et <y>
exactement , a&b
ne correspondrait jamais car il » ny a pas de chaîne de ce type qui peut être à la fois a
et b
en même temps).
Si les motifs ne se chevauchent pas, vous pouvez également faire:
grep -e "pattern1.*pattern2" -e "pattern2.*pattern1"
Le meilleur moyen portable est probablement avec awk
comme déjà mentionné:
awk "/pattern1/ && /pattern2/"
Avec sed
:
sed -e "/pattern1/!d" -e "/pattern2/!d"
Veuillez noter que tous ceux-ci auront une syntaxe dexpression régulière différente.
Commentaires
- La syntaxe
agrep
ne fonctionne pas pour moi … dans quelle version a-t-il été introduit? - @Raman 2.04 de 1992 lavait déjà. Je ‘ n’a aucune raison de croire qu’il n’y était pas ‘ depuis le début. Des versions plus récentes (après 1992) de
agrep
peuvent être trouvées incluses avec glimpse / webglimpse . Vous avez peut-être une implémentation différente. Jai eu une erreur pour la version ast-grep cependant, loption pour regexps augmentés est-X
, pas-A
. - @St é phaneChazelas Merci, jai
agrep
0.8.0 sur Fedora 23. Cela semble être unagrep
différent de celui auquel vous faites référence. - @Raman, le vôtre ressemble à TRE
agrep
. - @Techiee, ou simplement
awk '/p1/ && /p2/ {n++}; END {print 0+n}'
Réponse
Vous navez pas spécifié la version de grep, cest important. Certains moteurs dexpressions rationnelles autorisent plusieurs correspondances groupées par AND en utilisant « & « mais ce nest pas une fonctionnalité standard et non portable. Mais, au moins GNU grep ne prend pas en charge cela.
OTOH vous pouvez simplement remplacer grep par sed, awk, perl, etc. (classés par ordre croissant de poids). Avec awk, la commande ressemblerait à
awk "/regexp1/ && /regexp2/ && /regexp3/ { print; }"
et elle peut être construite pour être spécifiée en ligne de commande de manière simple.
Commentaires
- Souvenez-vous simplement que
awk
utilise des ERE ‘ s, par exemple léquivalent degrep -E
, par opposition aux BRE ‘ s utilisés pargrep
. Les expressions rationnelles -
awk
‘ sont appelées ERE, mais en fait elles ‘ est un peu idiosyncratique. Voici probablement plus de détails que quiconque ne souhaite: wiki.alpinelinux.org/wiki/Regex - Merci, grep 2.7.3 ( openSUSE). Je vous ai voté pour, mais je vais garder la question ouverte pendant un certain temps, peut-être quil y a une astuce pour grep (pas que je naime pas
awk
– simplement en savoir plus, cest mieux). - Laction par défaut est dimprimer la ligne correspondante de sorte que la partie
{ print; }
nest ‘ pas vraiment nécessaire ou utile ici.
Réponse
Si patterns
contient un motif par ligne, vous pouvez faire quelque chose comme ceci:
awk "NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1" patterns -
Ou cela correspond à des sous-chaînes au lieu de regular expressions:
awk "NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1" patterns -
Pour imprimer tout au lieu de pas de lignes de lentrée dans le si patterns
est vide, remplacez NR==FNR
par FILENAME==ARGV[1]
, ou par ARGIND==1
in gawk
.
Ces fonctions impriment les lignes de STDIN qui contiennent chaque chaîne spécifiée comme argument comme sous-chaîne. ga
signifie grep all et gai
ignore la casse.
ga(){ awk "FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1" <(printf %s\\n "$@") -; } gai(){ awk "FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1" <(printf %s\\n "$@") -; }
Commentaires
- réponse claire qui aborde plusieurs cas dusages et fonctionne (vérifiée sur macos)
Réponse
grep pattern1 | grep pattern2 | ...
Je voudrais utiliser un seul grep car je construis des arguments dynamiquement , donc tout doit tenir dans une chaîne
Il est en fait possible de construire le pipeline dynamiquement (sans recourir à eval
):
# Executes: grep "$1" | grep "$2" | grep "$3" | ... function chained-grep { local pattern="$1" if [[ -z "$pattern" ]]; then cat return fi shift grep -- "$pattern" | chained-grep "$@" } cat something | chained-grep all patterns must match order but matter dont
Ce nest probablement pas une solution très efficace.
Commentaires
- Utilisez soit
chained-grep()
soitfunction chained-grep
mais pasfunction chained-grep()
: unix.stackexchange.com/questions/73750/… - Pouvez-vous décrire lastuce? Pouvez-vous lajouter à la réponse ( sans » Edit: « , » Mettre à jour: « , ou similaire) en le modifier ?
- Reformulé la réponse pour rendre le truc plus clair (cest-à-dire: construire dynamiquement un pipeline shell)
Réponse
git grep
Voici la syntaxe utilisant git grep
combinaison de plusieurs modèles à laide dexpressions booléennes :
git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3
La commande ci-dessus imprimera les lignes correspondant à tous les modèles à la fois.
--no-index
Rechercher des fichiers dans le répertoire courant qui nest pas géré par Git.
Cochez man git-grep
pour obtenir de laide.
Voir aussi:
- Comment nous e grep pour correspondre à string1 AND string2?
- Vérifiez si toutes les chaînes ou expressions régulières existent dans un fichier .
Pour lopération OR , voir:
- Comment puis-je grep pour plusieurs motifs avec motif comportant un caractère pipe?
- Grep: comment ajouter un » OU » condition?
Commentaires
- Superbe réponse. Merci.
Réponse
Voici mon avis, et cela fonctionne pour les mots sur plusieurs lignes:
Utilisez find . -type f
suivi dautant de
-exec grep -q "first_word" {} \;
et le dernier mot-clé avec
-exec grep -l "nth_word" {} \;
-q
quiet / silent
-l
afficher les fichiers avec des correspondances
La liste suivante renvoie la liste des noms de fichiers contenant les mots « lapin » et « trou »:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;
Commentaires
- Si vous regardez attentivement, vous apprendrez peut-être que ce nest pas la fonctionnalité que la question demande.
Réponse
ripgrep
Voici lexemple utilisant rg
:
rg -N "(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)" file.txt
Cest lun des outils de grepping les plus rapides, car il est construit au-dessus de iv id = GH-875 .
Réponse
Pour trouver tous les mots (ou modèles), vous pouvez exécuter grep
dans une boucle for
. Le principal avantage ici est de rechercher dans une liste dexpressions régulières .
Un vrai exemple:
# File "search_all_regex_and_error_if_missing.sh" find_list="\ ^a+$ \ ^b+$ \ ^h+$ \ ^d+$ \ " for item in $find_list; do if grep -E "$item" file_to_search_within.txt then echo "$item found in file." else echo "Error: $item not found in file. Exiting!" exit 1 fi done
Maintenant, exécutons-le sur ce fichier:
hhhhhhhhhh aaaaaaa bbbbbbbbb ababbabaabbaaa ccccccc dsfsdf bbbb cccdd aa caa
$ ./search_all_regex_and_error_if_missing.sh aaaaaaa aa ^a+$ found in file. bbbbbbbbb bbbb ^b+$ found in file. hhhhhhhhhh ^h+$ found in file. Error: ^d+$ not found in file. Exiting!
Commentaires
- Votre logique est défectueuse – Jai demandé
ALL
, votre code fonctionne commeOR
opérateur, pasAND
. Et btw. Pour cela (OR
) est une solution beaucoup plus simple donnée directement dans la question. - @greenoldman La logique est simple: la boucle for sur TOUS les mots / motifs dans la liste, et sil est trouvé dans le fichier – limprimera. Donc, supprimez simplement le else si vous navez ‘ pas besoin daction si le mot na pas été trouvé.
- Je comprends votre logique ainsi que ma question – je vous posais une question sur lopérateur
AND
, ce qui signifie que le fichier nest quun résultat positif sil correspond au modèle A et au modèle B et motif C et …AND
Dans votre cas, le fichier est positif sil est tches le motif A ou le motif B ou … Voyez-vous la différence maintenant? - @greenoldman ne sais pas pourquoi vous pensez que cette boucle ne vérifie pas la condition AND pour tous les motifs? Jai donc ‘ édité ma réponse avec un exemple réel: il recherchera dans le fichier tous les regex de la liste, et sur le premier qui manque, il se terminera avec une erreur.
- Vous lavez juste devant vos yeux, vous avez une correspondance positive juste après lexécution de la première correspondance. Vous devriez avoir » collecter » tous les résultats et calculer
AND
dessus. Ensuite, vous devriez réécrire le script pour quil sexécute sur plusieurs fichiers – alors peut-être que vous vous rendez compte que la question a déjà reçu une réponse et que votre tentative napporte rien à la table, désolé.
foo
et les lignes contenantbar
» voir utiliser grep pour plusieurs modèles de recherche