Utilisez la syntaxe grep --exclude / - include pour ne pas grep via certains fichiers

780

Je recherche la chaîne foo=dans des fichiers texte dans une arborescence de répertoires. C'est sur une machine Linux commune, j'ai un shell bash:

grep -ircl "foo=" *

Les répertoires contiennent également de nombreux fichiers binaires qui correspondent à "foo =". Comme ces résultats ne sont pas pertinents et ralentissent la recherche, je veux que grep ignore la recherche de ces fichiers (principalement des images JPEG et PNG). Comment pourrais-je faire ça?

Je sais qu'il existe des options --exclude=PATTERNet --include=PATTERN, mais quel est le format du modèle? La page de manuel de grep dit:

--include=PATTERN     Recurse in directories only searching file matching PATTERN.
--exclude=PATTERN     Recurse in directories skip file matching PATTERN.

La recherche sur grep include , grep include exclude , grep exclude et les variantes n'ont trouvé rien de pertinent

S'il n'y a une meilleure façon de saluer que dans certains fichiers, je suis tout à fait d'accord; déplacer les fichiers incriminés n'est pas une option. Je ne peux pas rechercher uniquement certains répertoires (la structure des répertoires est un gros gâchis, avec tout partout). De plus, je ne peux rien installer, donc je dois faire avec des outils communs (comme grep ou la découverte suggérée ).

Piskvor a quitté le bâtiment
la source
13
Juste pour info, les arguments utilisés: -c compte les correspondances dans le fichier -i insensible à la casse -l n'affiche que les fichiers correspondants -r récursif
Piskvor a quitté le bâtiment
68
Un moyen plus rapide d'exclure les répertoires svn est --exclude-dir=.svn, donc grep n'y va pas du tout
orip
25
Quelques points pédantes que les gens peuvent avoir besoin de savoir: 1. Notez le manque de guillemets autour du globe ici: --exclude = ' . {Png, jpg}' ne fonctionne pas (au moins avec ma version GNU grep) parce que grep ne prend pas en charge {} dans ses globes. Ce qui précède est développé en shell pour '--exclude = .png --exclude = *. Jpg' (en supposant qu'aucun fichier ne correspond dans le cwd - très peu probable car vous ne démarrez pas normalement les noms de fichiers avec '--exclude =') qui grep aime très bien. 2. --exclude est une extension GNU et ne fait pas partie de la définition de grep par POSIX, donc si vous écrivez des scripts en utilisant ceci, sachez qu'ils ne s'exécuteront pas nécessairement sur des systèmes non GNU.
ijw
2
Exemple complet d'utilisation du répertoire d'exclusion:grep -r --exclude-dir=var "pattern" .
Tisch

Réponses:

767

Utilisez la syntaxe de globbing shell:

grep pattern -r --include=\*.{cpp,h} rootdir

La syntaxe de --excludeest identique.

Notez que l'étoile est échappée avec une barre oblique inverse pour l'empêcher d'être développée par le shell (la citer, comme, par exemple --include="*.{cpp,h}", fonctionnerait tout aussi bien). Sinon, si vous aviez des fichiers dans le répertoire de travail actuel qui correspondaient au modèle, la ligne de commande se développerait en quelque chose comme grep pattern -r --include=foo.cpp --include=bar.h rootdir, qui ne rechercherait que les fichiers nommés foo.cppet bar.h, ce qui n'est probablement pas ce que vous vouliez.

Adam Rosenfield
la source
8
Je ne sais pas pourquoi, mais j'ai dû citer le modèle d'inclusion comme ceci:grep pattern -r --include="*.{cpp,h}" rootdir
topek
6
@topek: Bon point - si vous avez des fichiers .cpp / .h dans votre répertoire actuel, le shell étendra le glob avant d'appeler grep, donc vous vous retrouverez avec une ligne de commande comme grep pattern -r --include=foo.cpp --include=bar.h rootdir, qui ne recherchera que les fichiers nommé foo.cppou bar.h. Si vous n'avez aucun fichier correspondant au glob dans le répertoire courant, le shell transmet le glob à grep, qui l'interprète correctement.
Adam Rosenfield
6
Je viens de réaliser que le glob est utilisé uniquement pour faire correspondre le nom de fichier. Pour exclure un répertoire entier, il faut une --exclude-diroption. Les mêmes règles s'appliquent cependant. Seul le nom de fichier du répertoire correspond, pas un chemin.
Krzysztof Jabłoński du
3
--includene semble pas fonctionner après --exclude. Je suppose que cela n'a même pas de sens d'essayer, sauf que j'ai un aliasà grep avec une longue liste de --excludeet --exclude-dir, que j'utilise pour rechercher du code, ignorer les bibliothèques et échanger des fichiers et des choses. J'aurais espéré que grep -r --exclude='*.foo' --include='*.bar'cela fonctionnerait, donc je pourrais me limiter aliasà --include='*.bar'seulement, mais il semble ignorer le --includeet inclure tout ce qui n'est pas un fichier .foo. Permuter l'ordre des --includeet --excludefonctionne, mais hélas, ce n'est pas utile avec mon alias.
Michael Scheper
1
comment pouvons-nous lire l'esprit de quelqu'un pour obtenir des règles à ce sujet PATTERN. Une demi-heure, je ne trouve aucune description de ce qu'ils attendent là-bas
Arkady
221

Si vous souhaitez simplement ignorer les fichiers binaires, je vous suggère de regarder l' -Ioption (majuscule i). Il ignore les fichiers binaires. J'utilise régulièrement la commande suivante:

grep -rI --exclude-dir="\.svn" "pattern" *

Il recherche récursivement, ignore les fichiers binaires et ne regarde pas à l'intérieur des dossiers cachés de Subversion, quel que soit le motif que je veux. Je l'ai aliasé "grepsvn" sur ma boîte au travail.

rmeador
la source
1
Merci, c'est très utile pour certains autres scénarios que j'ai rencontrés.
Piskvor a quitté le bâtiment
25
--exclude-dirn'est pas disponible partout. ma boîte RH au travail avec GNU grep 2.5.1 ne l'a pas.
gcb
Des suggestions sur ce qu'il faut utiliser lorsque --exclude-dirn'est pas disponible? Dans toutes mes tentatives, --excludene semble pas correspondre à la facture.
JMTyler
Vous pouvez toujours télécharger la dernière source grep depuis GNU, et faire une 'configure; faire; sudo make install '. C'est l'une des premières choses que je fais sur un Mac ou une distribution Linunx plus ancienne.
Jonathan Hartley
3
Exactement ce dont j'avais besoin. En fait, j'utilise git. Ainsi, --exclude-dir="\.git". :-)
Ionică Bizău
66

Veuillez jeter un œil à ack , qui est conçu exactement pour ces situations. Votre exemple de

grep -ircl --exclude=*.{png,jpg} "foo=" *

se fait avec ack comme

ack -icl "foo="

car ack ne regarde jamais dans les fichiers binaires par défaut, et -r est activé par défaut. Et si vous ne voulez que des fichiers CPP et H, faites simplement

ack -icl --cpp "foo="
Andy Lester
la source
C'est joli, j'essaierai la version autonome de Perl la prochaine fois, merci.
Piskvor a quitté le bâtiment
5
Bon appel, je ne peux plus vivre sans ack.
Chance
1
stackoverflow.com/questions/667471/… - Cela vous permettra d'obtenir un accusé de réception sur Windows, si c'est de là que vous exécutez grep.
TamusJRoyce
@Chance Peut-être que vous voulez silversearcher-ag , juste apt-getdans Ubuntu :)
Justme0
à ne pas confondre avecawk
jasonleonhard
35

grep 2.5.3 a introduit le paramètre --exclude-dir qui fonctionnera comme vous le souhaitez.

grep -rI --exclude-dir=\.svn PATTERN .

Vous pouvez également définir une variable d'environnement: GREP_OPTIONS = "- exclude-dir = .svn"

Je vais cependant seconder le vote d' Andy pour l' ack , c'est le meilleur.

Corey
la source
7
+1 pour avoir mentionné le numéro de version exact; J'ai grep 2.5.1 et l'option exclude-dir n'est pas disponible
James
25

J'ai trouvé cela après longtemps, vous pouvez ajouter plusieurs inclusions et exclusions comme:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js
Rushabh Mehta
la source
5
Il est préférable de les combiner dans une liste comme: --exclude = {pattern1, pattern2, pattern3}
Yasser Sinjab
12

La commande suggérée:

grep -Ir --exclude="*\.svn*" "pattern" *

est conceptuellement faux, car --exclude fonctionne sur le nom de base. Autrement dit, il ne sautera que le .svn dans le répertoire courant.


la source
3
Oui, ça ne marche pas du tout pour moi. Celui qui a fonctionné pour moi était: exclude-dir = .svn
Taryn East
2
@Nicola merci! J'ai arraché mes cheveux pour savoir pourquoi cela ne fonctionnerait pas. Dites-moi, existe-t-il un moyen de découvrir cela à partir de la page de manuel? Tout ce qu'il dit c'est qu'il correspond à "PATTERN". La page de manuel EDIT dit "file", comme expliqué ici fixunix.com/unix/…
13ren
11

Dans grep 2.5.1, vous devez ajouter cette ligne au profil ~ / .bashrc ou ~ / .bash

export GREP_OPTIONS="--exclude=\*.svn\*"
deric
la source
9

Je trouve que la sortie de grep grep est très utile parfois:

grep -rn "foo=" . | grep -v "Binary file"

Cependant, cela ne l'empêche pas de rechercher les fichiers binaires.

Aaron Maenpaa
la source
10
Vous pouvez utiliser grep -Ipour ignorer les fichiers binaires.
Nathan Fellman
J'ai aussi fait ça quand j'étais jeune ... maintenant je sais mieux et face à un problème, la première chose est RTFM
gcb
grep grep supprimera les reflets de couleur.
Max Li
7

Si vous n'êtes pas opposé à l'utilisation find, j'aime sa -prunefonctionnalité:

find [directory] \
        -name "pattern_to_exclude" -prune \
     -o -name "another_pattern_to_exclude" -prune \
     -o -name "pattern_to_INCLUDE" -print0 \
| xargs -0 -I FILENAME grep -IR "pattern" FILENAME

Sur la première ligne, vous spécifiez le répertoire que vous souhaitez rechercher. .(répertoire courant) est un chemin valide, par exemple.

Sur les 2e et 3e lignes, l' utilisation "*.png", "*.gif", "*.jpg"et ainsi de suite. Utilisez autant de ces -o -name "..." -pruneconstructions que vous avez de motifs.

Sur la 4ème ligne, vous en avez besoin d'un autre -o(il spécifie "ou" à find), les motifs que vous voulez, et vous avez besoin d'un -printou -print0à la fin. Si vous voulez juste « tout le reste » qui reste après la taille du *.gif, *.png, etc. images, puis utilisez -o -print0et vous avez terminé avec la ligne 4.

Enfin, sur la 5ème ligne se trouve le canal vers xargslequel prend chacun de ces fichiers résultants et les stocke dans une variable FILENAME. Il passe ensuite greples -IRdrapeaux, le "pattern", puis FILENAMEest développé par xargspour devenir la liste des noms de fichiers trouvés par find.

Pour votre question particulière, la déclaration peut ressembler à quelque chose comme:

find . \
     -name "*.png" -prune \
     -o -name "*.gif" -prune \
     -o -name "*.svn" -prune \
     -o -print0 | xargs -0 -I FILES grep -IR "foo=" FILES

OnlineCop
la source
Un amendement que je suggérerais: inclure -falseimmédiatement après chaque -pruneafin d'oublier d'utiliser -print0ou une sorte de execcommande n'imprimera pas réellement les fichiers que vous vouliez exclure: -name "*.png" -prune -false -o name "*.gif -prune -false...
OnlineCop
7

Sur CentOS 6.6 / Grep 2.6.3, je dois l'utiliser comme ceci:

grep "term" -Hnir --include \*.php --exclude-dir "*excluded_dir*"

Notez l'absence de signe égal « = » (sinon --include, --exclude, include-diret --exclude-dirsont ignorées)

aesede
la source
6

git grep

Utilisation git grepoptimisée pour les performances et visant à rechercher dans certains fichiers.

Par défaut, il ignore les fichiers binaires et respecte votre .gitignore. Si vous ne travaillez pas avec la structure Git, vous pouvez toujours l'utiliser en passant --no-index.

Exemple de syntaxe:

git grep --no-index "some_pattern"

Pour plus d'exemples, voir:

kenorb
la source
5

Je suis dilettante, d'accord, mais voici à quoi ressemble mon ~ / .bash_profile:

export GREP_OPTIONS = "- orl --exclude-dir = .svn --exclude-dir = .cache --color = auto" GREP_COLOR = '1; 32'

Notez que pour exclure deux répertoires, j'ai dû utiliser --exclude-dir deux fois.

4D4M
la source
3

Si vous effectuez une recherche non récursive, vous pouvez utiliser des modèles Glop pour faire correspondre les noms de fichiers.

grep "foo" *.{html,txt}

comprend html et txt. Il recherche uniquement dans le répertoire courant.

Pour rechercher dans les sous-répertoires:

   grep "foo" */*.{html,txt}

Dans les sous-répertoires:

   grep "foo" */*/*.{html,txt}
Stéphane Laurent
la source
3

Dans les répertoires se trouvent également de nombreux fichiers binaires. Je ne peux pas rechercher uniquement certains répertoires (la structure des répertoires est un gros gâchis). Existe-t-il une meilleure façon de saluer uniquement dans certains fichiers?

ripgrep

Il s'agit de l'un des outils les plus rapides conçus pour rechercher récursivement votre répertoire actuel. Il est écrit en Rust , construit sur le moteur regex de Rust pour une efficacité maximale. Consultez l' analyse détaillée ici .

Vous pouvez donc simplement exécuter:

rg "some_pattern"

Il respecte votre .gitignoreet ignore automatiquement les fichiers / répertoires cachés et les fichiers binaires.

Vous pouvez toujours personnaliser l'inclusion ou l'exclusion de fichiers et de répertoires à l'aide de -g/ --glob. Les règles globales correspondent aux .gitignoreglobes. Cherchez man rgde l'aide.

Pour plus d'exemples, voir: Comment exclure certains fichiers ne correspondant pas à certaines extensions avec grep?

Sur macOS, vous pouvez installer via brew install ripgrep.

kenorb
la source
3

find et xargs sont vos amis. Utilisez-les pour filtrer la liste des fichiers plutôt que celle de grep --exclude

Essayez quelque chose comme

find . -not -name '*.png' -o -type f -print | xargs grep -icl "foo="

L'avantage de s'y habituer est qu'il est extensible à d'autres cas d'utilisation, par exemple pour compter les lignes dans tous les fichiers non png:

find . -not -name '*.png' -o -type f -print | xargs wc -l

Pour supprimer tous les fichiers non png:

find . -not -name '*.png' -o -type f -print | xargs rm

etc.

Comme indiqué dans les commentaires, si certains fichiers peuvent avoir des espaces dans leurs noms, utilisez -print0et à la xargs -0place.

Andrew Stein
la source
1
Cela ne fonctionne pas sur les noms de fichiers avec des espaces, mais ce problème est facilement résolu en utilisant print0 au lieu de print et en ajoutant l'option -0 à xargs.
Adam Rosenfield
2

ces scripts n'accomplissent pas tout le problème ... Essayez mieux:

du -ha | grep -i -o "\./.*" | grep -v "\.svn\|another_file\|another_folder" | xargs grep -i -n "$1"

ce script est tellement meilleur, car il utilise des expressions régulières "réelles" pour éviter les répertoires de la recherche. séparez simplement les noms de dossier ou de fichier par "\ |" sur le grep -v

Profitez-en! trouvé sur mon shell linux! XD


la source
2

Regardez @ celui-ci.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags
suhas tawade
la source
2
Les choses qui permettent d'atteindre cet objectif ont été traitées dans d'autres articles; De plus, c'est faux, car avec diverses options de mise en page définies, il gâchera les numéros de ligne et des choses comme ça ou exclura les lignes de contexte souhaitées.
Chris Morgan
comment pouvez-vous utiliser plusieurs options "-v" en même temps?
Ouvrez la voie
1

L' --binary-files=without-matchoption GNU greppermet de sauter les fichiers binaires. (Équivalent au -Icommutateur mentionné ailleurs.)

(Cela peut nécessiter une version récente de grep; 2.5.3 l'a au moins.)

mjs
la source
1

adapté au fichier tcsh .alias:

alias gisrc 'grep -I -r -i --exclude="*\.svn*" --include="*\."{mm,m,h,cc,c} \!* *'

Il m'a fallu un certain temps pour comprendre que la partie {mm, m, h, cc, c} ne devait PAS être entre guillemets. ~ Keith

Keith Knauber
la source
0

Pour ignorer tous les résultats binaires de grep

grep -Ri "pattern" * | awk '{if($1 != "Binary") print $0}'

La partie awk filtrera toutes les lignes de correspondance du fichier binaire foo

lathomas64
la source
-2

Essaye ça:

  1. Créez un dossier nommé " --F" sous currdir .. (ou liez un autre dossier renommé à " --F" ie double-minus-F.
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
P pile
la source