Verwenden Sie die Syntax grep --exclude / - include, um bestimmte Dateien nicht zu durchsuchen

780

Ich suche die Zeichenfolge foo=in Textdateien in einem Verzeichnisbaum. Es ist auf einem gemeinsamen Linux-Computer, ich habe Bash-Shell:

grep -ircl "foo=" *

In den Verzeichnissen befinden sich auch viele Binärdateien, die mit "foo =" übereinstimmen. Da diese Ergebnisse nicht relevant sind und die Suche verlangsamen, möchte ich, dass grep die Suche in diesen Dateien überspringt (hauptsächlich JPEG- und PNG-Bilder). Wie würde ich das machen?

Ich weiß, dass es die --exclude=PATTERNund --include=PATTERNOptionen gibt, aber wie ist das Musterformat? Die Manpage von grep sagt:

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

Die Suche auf grep include , grep include exclude , grep exclude und Varianten hat nichts Relevantes gefunden

Wenn es eine bessere Möglichkeit gibt, nur in bestimmten Dateien zu greifen, bin ich alles dafür; Das Verschieben der fehlerhaften Dateien ist keine Option. Ich kann nicht nur bestimmte Verzeichnisse durchsuchen (die Verzeichnisstruktur ist ein großes Durcheinander, mit allem überall). Außerdem kann ich nichts installieren, daher habe ich mit gängigen Tools zu tun (wie grep oder dem vorgeschlagenen Fund ).

Piskvor verließ das Gebäude
quelle
13
Nur
berücksichtigt
68
Ein schnellerer Weg, um SVN-Verzeichnisse auszuschließen, ist --exclude-dir=.svn, dass Grep überhaupt nicht darauf
eingeht
25
Einige pedantische Punkte, die die Leute möglicherweise wissen müssen: 1. Beachten Sie das Fehlen von Anführungszeichen rund um den Globus hier: --exclude = ' . {Png, jpg}' funktioniert nicht (zumindest mit meiner GNU-Grep-Version), weil grep unterstützt {} in seinen Globs nicht. Das Obige wird durch die Shell auf '--exclude = .png --exclude = *. Jpg' erweitert (vorausgesetzt, dass keine Dateien im cwd übereinstimmen - sehr unwahrscheinlich, da Sie Dateinamen normalerweise nicht mit '--exclude =' starten) grep mag ganz gut. 2. --exclude ist eine GNU-Erweiterung und nicht Teil der POSIX-Definition von grep. Wenn Sie also Skripte damit schreiben, müssen Sie beachten, dass sie nicht unbedingt auf Nicht-GNU-Systemen ausgeführt werden.
ijw
2
Vollständiges Beispiel für die Verwendung von Ausschlussverzeichnissen:grep -r --exclude-dir=var "pattern" .
Tisch

Antworten:

767

Verwenden Sie die Shell-Globbing-Syntax:

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

Die Syntax für --excludeist identisch.

Beachten Sie, dass der Stern mit einem Backslash versehen wird, um zu verhindern, dass er von der Shell erweitert wird (wenn Sie ihn zitieren --include="*.{cpp,h}", würde dies genauso gut funktionieren). Wenn Sie andernfalls Dateien im aktuellen Arbeitsverzeichnis hätten, die dem Muster entsprechen, würde die Befehlszeile so erweitert grep pattern -r --include=foo.cpp --include=bar.h rootdir, dass nur Dateien mit dem Namen durchsucht werden foo.cppund bar.hwas höchstwahrscheinlich nicht das ist, was Sie wollten.

Adam Rosenfield
quelle
8
Ich weiß nicht warum, aber ich musste das Include-Muster wie grep pattern -r --include="*.{cpp,h}" rootdir
folgt
6
@topek: Guter Punkt - Wenn sich in Ihrem aktuellen Verzeichnis CPP / H-Dateien befinden, erweitert die Shell den Glob vor dem Aufrufen von grep, sodass Sie eine Befehlszeile wie erhalten grep pattern -r --include=foo.cpp --include=bar.h rootdir, in der nur Dateien durchsucht werden benannt foo.cppoder bar.h. Wenn Sie keine Dateien haben, die mit dem Glob im aktuellen Verzeichnis übereinstimmen, gibt die Shell den Glob an grep weiter, der ihn korrekt interpretiert.
Adam Rosenfield
6
Ich habe gerade festgestellt, dass der Glob nur mit dem Dateinamen übereinstimmt. Um ein ganzes Verzeichnis auszuschließen, benötigt man eine --exclude-dirOption. Es gelten jedoch die gleichen Regeln. Es wird nur der Verzeichnisdateiname abgeglichen, kein Pfad.
Krzysztof Jabłoński
3
--includescheint danach nicht zu funktionieren --exclude. Ich nehme an, es macht keinen Sinn, es überhaupt zu versuchen, außer dass ich aliaseine lange Liste von --excludeund haben muss --exclude-dir, die ich zum Durchsuchen von Code, Ignorieren von Bibliotheken und Austauschen von Dateien und Dingen verwende. Ich hätte gehofft, dass grep -r --exclude='*.foo' --include='*.bar'das funktionieren würde, also könnte ich mich aliasauf --include='*.bar'nur beschränken, aber es scheint das zu ignorieren --includeund alles einzuschließen, was keine .foo-Datei ist. Das Vertauschen der Reihenfolge von --includeund --excludefunktioniert, aber leider ist das bei mir nicht hilfreich alias.
Michael Scheper
1
Wie können wir jemandes Kopf zu bekommen Regeln für diese Zeilen lesen PATTERN. Eine halbe Stunde kann ich keine Beschreibung finden, worauf sie dort warten
Arkady
221

Wenn Sie nur Binärdateien überspringen möchten, empfehlen wir Ihnen die -IOption (Großbuchstaben i). Binärdateien werden ignoriert. Ich benutze regelmäßig den folgenden Befehl:

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

Es sucht rekursiv, ignoriert Binärdateien und sucht nicht in versteckten Subversion-Ordnern nach dem gewünschten Muster. Ich habe es als "grepsvn" auf meiner Box bei der Arbeit aliased.

rmeador
quelle
1
Vielen Dank, das ist sehr nützlich für einige andere Szenarien, denen ich begegnet bin.
Piskvor verließ das Gebäude
25
--exclude-dirist nicht überall verfügbar. Meine RH-Box bei der Arbeit mit GNU grep 2.5.1 hat es nicht.
GCB
Irgendwelche Vorschläge, was zu verwenden ist, wenn --exclude-dires nicht verfügbar ist? In all meinen Versuchen --excludescheint nicht die Rechnung zu passen.
JMTyler
Sie können jederzeit die neueste grep-Quelle von GNU herunterladen und eine Konfiguration durchführen. machen; sudo make install '. Dies ist eines der ersten Dinge, die ich auf einem Mac oder einer älteren Linunx-Distribution mache.
Jonathan Hartley
3
Genau das, was ich brauchte. Eigentlich benutze ich Git. Also , --exclude-dir="\.git". :-)
Ionică Bizău
66

Bitte werfen Sie einen Blick auf ack , das genau für diese Situationen ausgelegt ist. Ihr Beispiel von

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

wird mit ack as gemacht

ack -icl "foo="

weil ack standardmäßig nie in Binärdateien sucht und -r standardmäßig aktiviert ist. Und wenn Sie nur CPP- und H-Dateien möchten, tun Sie dies einfach

ack -icl --cpp "foo="
Andy Lester
quelle
Sieht gut aus, werde das nächste Mal die eigenständige Perl-Version ausprobieren, danke.
Piskvor verließ das Gebäude
5
Guter Anruf, ich kann nicht mehr ohne Bestätigung leben.
Chance
1
stackoverflow.com/questions/667471/… - Auf diese Weise können Sie Windows überprüfen , wenn Sie dort grep ausführen .
TamusJRoyce
@Chance Vielleicht möchten Sie silversearcher-ag , nur apt-getin Ubuntu :)
Justme0
nicht zu verwechseln mitawk
jasonleonhard
35

In grep 2.5.3 wurde der Parameter --exclude-dir eingeführt, der wie gewünscht funktioniert.

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

Sie können auch eine Umgebungsvariable festlegen: GREP_OPTIONS = "- exclude-dir = .svn"

Ich werde Andys Stimme für ack unterstützen , es ist das Beste.

Corey
quelle
7
+1 für die Angabe der genauen Versionsnummer; Ich habe grep 2.5.1 und die Option exclude-dir ist nicht verfügbar
James
25

Ich fand dies nach langer Zeit, Sie können mehrere Ein- und Ausschlüsse hinzufügen wie:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js
Rushabh Mehta
quelle
5
Es ist besser, sie in einer Liste zu kombinieren wie: --exclude = {pattern1, pattern2, pattern3}
Yasser Sinjab
12

Der vorgeschlagene Befehl:

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

ist konzeptionell falsch, weil --exclude für den Basisnamen funktioniert. Mit anderen Worten, es wird nur die .svn im aktuellen Verzeichnis übersprungen.


quelle
3
Ja, es funktioniert überhaupt nicht für mich. Das, was für mich funktioniert hat, war: exclude-dir = .svn
Taryn East
2
@Nicola danke! Ich habe mir die Haare ausgerissen, warum das nicht funktioniert. Sag mir, gibt es eine Möglichkeit, dies auf der Manpage zu entdecken? Alles was es sagt ist, dass es mit "MUSTER" übereinstimmt. EDIT Manpage sagt "Datei", wie hier erklärt fixunix.com/unix/…
13ren
11

In grep 2.5.1 müssen Sie diese Zeile zum Profil ~ / .bashrc oder ~ / .bash hinzufügen

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

Ich finde die Ausgabe von grepping grep manchmal sehr hilfreich:

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

Das hindert es jedoch nicht daran, die Binärdateien zu durchsuchen.

Aaron Maenpaa
quelle
10
Sie können grep -IBinärdateien überspringen.
Nathan Fellman
habe das auch getan, als ich jung war ... jetzt weiß ich es besser und wenn ich mit einem Problem konfrontiert werde, ist RTFM
gcb
Wenn Sie grep grep verwenden, werden die Farbmarkierungen entfernt.
Max Li
7

Wenn Sie nicht abgeneigt sind find, mag ich seine -pruneFunktion:

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

In der ersten Zeile geben Sie das Verzeichnis an, nach dem Sie suchen möchten. .(aktuelles Verzeichnis) ist beispielsweise ein gültiger Pfad.

Am 2. und 3. Zeile, Verwendung "*.png", "*.gif", "*.jpg"und so weiter. Verwenden Sie so viele dieser -o -name "..." -pruneKonstrukte, wie Sie Muster haben.

In der 4. Zeile benötigen Sie ein anderes -o(es gibt "oder" bis find) an, die Muster, die Sie möchten, und Sie benötigen entweder ein -printoder -print0am Ende. Wenn Sie nur wollen „alles andere“ , die Überreste nach dem Beschneiden der *.gif, *.pngusw. Bilder, dann verwenden -o -print0und Sie sind mit der 4. Zeile getan.

Schließlich befindet sich in der 5. Zeile die Pipe, zu xargsder jede dieser resultierenden Dateien genommen und in einer Variablen gespeichert wird FILENAME. Es übergibt dann grepdie -IRFlags, "pattern"und wird dann um die Liste der Dateinamen FILENAMEerweitert xargs, die von gefunden wurden find.

Für Ihre spezielle Frage könnte die Aussage ungefähr so ​​aussehen:

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

OnlineCop
quelle
Eine Änderung, die ich vorschlagen würde: Fügen Sie -falsesofort nach jedem ein, -prunedamit das Vergessen der Verwendung -print0oder ein execBefehl die Dateien, die Sie ausschließen wollten, nicht druckt: -name "*.png" -prune -false -o name "*.gif -prune -false...
OnlineCop
7

Unter CentOS 6.6 / Grep 2.6.3 muss ich es folgendermaßen verwenden:

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

Beachten Sie die fehlende Gleichheitszeichen „=“ (sonst --include, --exclude, include-dirund --exclude-dirignoriert werden)

aesede
quelle
6

git grep

Verwendung, git grepdie für die Leistung optimiert ist und darauf abzielt, bestimmte Dateien zu durchsuchen.

Standardmäßig werden Binärdateien ignoriert und Ihre .gitignore. Wenn Sie nicht mit der Git-Struktur arbeiten, können Sie sie trotzdem durch Übergeben verwenden --no-index.

Beispielsyntax:

git grep --no-index "some_pattern"

Weitere Beispiele finden Sie unter:

Kenorb
quelle
5

Zugegeben, ich bin ein Dilettant, aber so sieht mein ~ / .bash_profile aus:

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

Beachten Sie, dass ich --exclude-dir zweimal verwenden musste, um zwei Verzeichnisse auszuschließen.

4D4M
quelle
3

Wenn Sie nicht rekursiv suchen, können Sie Glop-Muster verwenden , um die Dateinamen abzugleichen .

grep "foo" *.{html,txt}

enthält HTML und TXT. Es wird nur im aktuellen Verzeichnis gesucht.

So suchen Sie in den Unterverzeichnissen:

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

In den Unterverzeichnissen:

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

In den Verzeichnissen befinden sich auch viele Binärdateien. Ich kann nicht nur bestimmte Verzeichnisse durchsuchen (die Verzeichnisstruktur ist ein großes Durcheinander). Gibt es eine bessere Möglichkeit, nur in bestimmten Dateien zu greifen?

ripgrep

Dies ist eines der schnellsten Tools zum rekursiven Durchsuchen Ihres aktuellen Verzeichnisses. Es ist in Rust geschrieben und basiert auf Rusts Regex-Motor für maximale Effizienz. Überprüfen Sie die detaillierte Analyse hier .

Sie können also einfach ausführen:

rg "some_pattern"

Es respektiert Ihre .gitignoreund überspringt automatisch versteckte Dateien / Verzeichnisse und Binärdateien.

Sie können das Einschließen oder Ausschließen von Dateien und Verzeichnissen weiterhin mit -g/ anpassen --glob. Globbing-Regeln stimmen mit .gitignoreGlobs überein. Suchen Sie man rgnach Hilfe.

Weitere Beispiele finden Sie unter: Wie kann ich einige Dateien ausschließen, die bestimmten Erweiterungen nicht mit grep entsprechen?

Unter macOS können Sie über installieren brew install ripgrep.

Kenorb
quelle
3

find und xargs sind deine Freunde. Verwenden Sie sie, um die Dateiliste zu filtern, anstatt greps --exclude

Versuchen Sie etwas wie

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

Der Vorteil, sich daran zu gewöhnen, besteht darin, dass es auf andere Anwendungsfälle erweitert werden kann, z. B. um die Zeilen in allen Nicht-PNG-Dateien zu zählen:

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

So entfernen Sie alle Nicht-PNG-Dateien:

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

usw.

Wie in den Kommentaren erwähnt, verwenden Sie stattdessen -print0und , wenn einige Dateien Leerzeichen in ihren Namen haben xargs -0.

Andrew Stein
quelle
1
Dies funktioniert nicht bei Dateinamen mit Leerzeichen, aber dieses Problem lässt sich leicht lösen, indem Sie print0 anstelle von print verwenden und xargs die Option -0 hinzufügen.
Adam Rosenfield
2

Diese Skripte lösen nicht das ganze Problem ... Versuchen Sie es besser:

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

Dieses Skript ist so besser, weil es "echte" reguläre Ausdrücke verwendet, um Verzeichnisse bei der Suche zu vermeiden. Trennen Sie einfach Ordner- oder Dateinamen mit "\ |" auf dem grep -v

geniesse es! auf meiner Linux-Shell gefunden! XD


quelle
2

Schau mal bei diesem.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags
Suhas Tawade
quelle
2
Dinge, die ungefähr dies erreichen, wurden in anderen Beiträgen behandelt; Darüber hinaus ist dies insofern falsch, als bei verschiedenen Layoutoptionen Zeilennummern und ähnliches durcheinander gebracht oder gewünschte Kontextzeilen ausgeschlossen werden.
Chris Morgan
Wie können Sie mehrere "-v" -Optionen gleichzeitig verwenden?
Öffnen Sie den Weg
1

Mit der --binary-files=without-matchOption zu GNU grepkönnen Binärdateien übersprungen werden. (Entspricht dem an -Ianderer Stelle genannten Schalter.)

(Dies erfordert möglicherweise eine neuere Version von grep; 2.5.3 hat es zumindest.)

mjs
quelle
1

geeignet für tcsh .alias Datei:

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

Ich habe eine Weile gebraucht, um herauszufinden, dass der Teil {mm, m, h, cc, c} NICHT in Anführungszeichen stehen sollte. ~ Keith

Keith Knauber
quelle
0

Alle binären Ergebnisse von grep ignorieren

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

Der awk-Teil filtert alle Foo-Übereinstimmungszeilen der Binärdatei heraus

lathomas64
quelle
-2

Versuche dies:

  1. Erstellen Sie einen Ordner mit dem Namen " --F" unter currdir .. (oder verknüpfen Sie einen anderen Ordner, der dort in " --F" umbenannt wurde) double-minus-F.
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
P Stapel
quelle