Je voudrais obtenir la correspondance multi-modèles avec implicitement ET entre les modèles, c'est-à-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 grep unique car je construis des arguments dynamiquement, donc tout doit tenir dans une seule chaîne. L'utilisation du filtre est une fonction système, pas grep, donc ce n'est pas un argument pour cela.
Ne confondez pas cette question avec:
grep "pattern1\|pattern2\|..."
Il s'agit d'une OU correspondance de plusieurs motifs.
agrep
peut le faire avec cette syntaxe:
agrep 'pattern1;pattern2'
Avec GNU grep
, lorsqu'il est construit avec le support PCRE, vous pouvez faire:
grep -P '^(?=.*pattern1)(?=.*pattern2)'
Avec ast grep
:
grep -X '.*pattern1.*&.*pattern2.*'
(ajouter .*
s comme <x>&<y>
correspond à des chaînes qui correspondent aux deux <x>
et <y>
exactement , a&b
ne correspondrait jamais car il n'y a pas une telle chaîne qui peut être 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 d'expression régulière différente.
Vous n'avez pas spécifié de version grep, c'est important. Certains moteurs d'expression régulière autorisent plusieurs correspondances regroupées par ET en utilisant "&", mais il s'agit d'une fonctionnalité non 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 d'augmentation de poids). Avec awk, la commande ressemblerait à
awk '/ regexp1/&&/regexp2/&&/regexp3/{print; } '
et il peut être construit pour être spécifié en ligne de commande de manière simple.
Ce n'est pas une très bonne solution mais illustre un "truc" plutôt cool
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
Si patterns
contient un modèle 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 d'expressions régulières:
awk 'NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1' patterns -
Pour imprimer toutes les lignes de l’entrée au lieu d’aucune ligne dans le cas où patterns
est vide, remplacez NR==FNR
avec FILENAME==ARGV[1]
, ou avec ARGIND==1
dans gawk
.
Ces fonctions affichent 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 "$@") -; }
git grep
Voici la syntaxe utilisant git grep
combinant plusieurs modèles à l'aide des expressions booléennes :
git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3
La commande ci-dessus imprime des lignes correspondant à tous les motifs à la fois.
--no-index
Rechercher des fichiers dans le répertoire courant qui ne sont pas gérés par Git.
Vérifier man git-grep
pour aider.
Voir également:
Pour le fonctionnement [~ # ~] ou [~ # ~] , voir:
Voici mon point de vue, et cela fonctionne pour les mots sur plusieurs lignes:
Utilisation find . -type f
suivi par autant-exec grep -q 'first_Word' {} \;
et le dernier mot-clé avec-exec grep -l 'nth_Word' {} \;
-q
calme/silencieux-l
afficher les fichiers avec des correspondances
La liste suivante renvoie les noms de fichiers contenant les mots "lapin" et "trou":find . -type f -exec grep -q 'rabbit' {} \; -exec grep -l 'hole' {} \;
ripgrep
Voici l'exemple utilisant rg
:
rg -N '(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)' file.txt
C'est l'un des outils de grepping les plus rapides, car il est construit sur le moteur regex de Rust qui utilise des automates finis, SIMD et des optimisations littérales agressives pour rendre la recherche très rapide.
Voir également la demande de fonctionnalité associée sur GH-875 .
Cette commande Shell peut aider:
eval "</dev/stdin $(printf "|grep '%s'" pattern1 pattern2)" FILE
Cependant, c'est plus facile si tous vos modèles sont stockés dans le fichier, vous pouvez donc définir l'alias suivant:
alias grep-all="cat $(xargs printf '| grep "%s"' < patterns.txt)"
et l'utiliser comme:
cat text.txt | grep-all
Vous pouvez bien sûr modifier l'alias en fonction de votre syntaxe requise, donc avec cet alias:
alias grep-all="</dev/stdin $(xargs printf '|grep "%s"' < patterns.txt)"
vous pouvez utiliser une seule commande, par exemple.
grep-all text.txt
Pour plus d'idées, vérifiez également: Faites correspondre tous les modèles du fichier à la fois .
Pour l'opération AND par fichier, voir: Vérifiez si toutes les chaînes ou expressions régulières multiples existent dans un fichier .