Wie verwende ich die Option grep --include für mehrere Dateitypen?

98

Wenn ich alle HTML-Dateien in einem Verzeichnis durchsuchen möchte, gehe ich wie folgt vor

grep --include="*.html" pattern -R /some/path

das funktioniert gut. Das Problem ist, wie man alle HTML-, HTML- und PHP-Dateien in einem Verzeichnis erfasst.

Aus dieser Verwendung der Syntax grep --exclude / - include, um bestimmte Dateien nicht zu durchsuchen , kann ich anscheinend Folgendes tun

grep --include="*.{html,php,htm}" pattern -R /some/path

Aber leider würde es bei mir nicht funktionieren.
Zu Ihrer Information, meine grep-Version ist 2.5.1.

Tianyapiaozi
quelle

Antworten:

136

Sie können mehrere --includeFlags verwenden. Das funktioniert bei mir:

grep -r --include=*.html --include=*.php --include=*.htm "pattern" /some/path/

Sie können jedoch wie Deruijtervorgeschlagen vorgehen. Das funktioniert bei mir:

grep -r --include=*.{html,php,htm} "pattern" /some/path/

Vergessen Sie nicht, dass Sie verwenden können findund xargsfür diese Art von Dingen:

find /some/path/ -name "*.htm*" -or -name "*.php" | xargs grep "pattern"

HTH

Steve
quelle
1
Ich sehe das Problem. Ich habe --include = " . { Html , php}" verwendet, um zu verhindern, dass sich die Shell erweitert ' ', wodurch gleichzeitig die Shell gestoppt wird, um {html, php} zu erweitern. Es scheint, dass das Gleichheitszeichen in --include = * verhindern kann, dass die Shell '*' erweitert.
Tianyapiaozi
xargs ist nicht wirklich ein Ersatz; Wenn Sie diese Funktion benötigen, haben Sie häufig mit mehr Dateien zu tun, als xargs verarbeiten kann.
James Moore
2
@ JamesMoore: Schauen Sie sich GNU Parallel an . Es kann oft als Ersatz für verwendet werden xargs. Dies ist auch eine kurze Lektüre wert. HTH.
Steve
3
@tianyapiaozi: Sie haben Recht, dass das Zitieren um die Klammererweiterung das Problem ist; jedoch ohne die Angabe, *steht noch unter Globbing als Teil der Token es in eingebettet ist , es ist einfach passiert , nicht zu Spiel etwas in diesem Fall, da nur Dateien buchstäblich einen Namen wie --include=foo.htmlpassen würde. Um sicher zu gehen, zitieren Sie das *(was Sie individuell tun können \*). Als zusätzlichen Bonus wird dadurch visuell klarer, dass in diesem Fall nicht die Shell das Globbing durchführen sollte.
mklement0
2
Was die findLösung betrifft: Die Verwendung von -exec grep "pattern" {} +anstelle von | xargs grep "pattern"ist robuster (behandelt Dateinamen beispielsweise mit Leerzeichen) sowie effizienter.
mklement0
32

Unter Verwendung {html,php,htm}kann als nur arbeitet Klammer Erweiterung , die ein Nicht - Standard (nicht POSIX-konform) Merkmal bash, kshund zsh.

  • Mit anderen Worten: Versuchen Sie nicht, es in einem Skript zu verwenden, das darauf abzielt. /bin/shVerwenden Sie in diesem Fall explizite Mehrfachargumente --include.

  • grepselbst nicht nicht verstehen {...}Notation.

Damit eine Klammererweiterung erkannt wird, muss es sich um ein nicht zitiertes (Teil eines) Tokens in der Befehlszeile handeln.

Eine Klammer Erweiterung dehnt sich mehrere Argumente , so im Fall zur Hand grepEnden nach oben sehen , mehrere --include=... Optionen, wie wenn man sie einzeln vergangen war.

Die Ergebnisse einer Klammererweiterung unterliegen einem Globbing (Dateinamenerweiterung) , das Fallstricke aufweist :

  • Jedes resultierende Argument könnte weiter auf übereinstimmende Dateinamen erweitert werden, wenn es nicht zitierte globale Zeichen enthält, wie z *.
    Während dies bei Token wie z. B. --include=*.html(z. B. müsste eine Datei buchstäblich so genannt werden , --include=foo.htmldamit etwas übereinstimmt) unwahrscheinlich ist, sollte dies im Allgemeinen beachtet werden.

  • Wenn die nullglobShell-Option zufällig shopt -s nullglobaktiviert ist ( ) und Globbing mit nichts übereinstimmt , wird das Argument verworfen .

Verwenden Sie daher für eine vollständig robuste Lösung Folgendes:

grep -R '--include=*.'{html,php,htm} pattern /some/path
  • '--include=*.'wird als wörtlich behandelt , weil es in einfachen Anführungszeichen steht ; Dies verhindert eine versehentliche Interpretation *als Globbing-Charakter.

  • {html,php,htm}Die - notgedrungen - unquoted Verstrebung Expansion [1] , erweitert zu 3 Argumente, die aufgrund {...} direkt die folgenden '...'Token , umfassen die Token.

  • Daher werden nach dem Entfernen des Anführungszeichens durch die Shell die folgenden 3 Literalargumente letztendlich an Folgendes übergebengrep :

    • --include=*.html
    • --include=*.php
    • --include=*.htm

[1] Genauer gesagt müssen nur die syntaxrelevanten Teile der Klammererweiterung nicht in Anführungszeichen gesetzt werden. Die Listenelemente können weiterhin einzeln in Anführungszeichen gesetzt werden und müssen, wenn sie Globbing-Metazeichen enthalten, zu unerwünschtem Globbing nach der Klammererweiterung führen. Obwohl dies in diesem Fall nicht erforderlich ist, könnte das oben Gesagte als geschrieben werden
'--include=*.'{'html','php','htm'}

mklement0
quelle
1
Vielen Dank für diesen Beitrag. Tolle Beiträge beantworten nicht nur die Frage, sondern bringen dir auch etwas Neues bei! Dies ist besonders nützlich für diejenigen von uns, die über etwas schreiben, das POSIX-kompatibel sein muss. Jeder, der Mac OS X verwendet, sollte hier nachsehen!
Sabalaba
@sabalaba: Ich bin froh, das zu hören, aber um es klar zu sagen: Während die Klammererweiterung nicht POSIX-kompatibel ist, funktioniert sie bashauf jeder Plattform, bashauf der sie ausgeführt wird.
mklement0
9

Versuchen Sie, die doppelten Anführungszeichen zu entfernen

grep --include=*.{html,php,htm} pattern -R /some/path
Deruijter
quelle
@ tianyapiaozi Versuchen Sie grep --include=\*.{html,php,htm} pattern -R /some/path. Es hat bei mir funktioniert.
Hyunjun Kim
4

funktioniert das nicht

  grep pattern  /some/path/*.{html,php,htm} 
Vijay
quelle
Nicht wirklich. Die Dateien können sich im Unterverzeichnis des Unterverzeichnisses
tianyapiaozi
2

Versuche dies. -r führt eine rekursive Suche durch. -s unterdrückt Fehler, bei denen keine Datei gefunden wurde. -n zeigt Ihnen die Zeilennummer der Datei an, in der sich das Muster befindet.

    grep "pattern" <path> -r -s -n --include=*.{c,cpp,C,h}
Pradeep
quelle
Dies ist die beste Antwort für mich, und ich denke, Sie können -rsn anstelle von -r -s -n setzen (aber das ist kein Problem).
schlank
Normalerweise benutze ich -rns . Zur Verdeutlichung im Beispiel musste ich -r -n -s erwähnen :-) Ich bin froh, dass es geholfen hat.
Pradeep
Ich empfehle -I, das Standard-Set zu ergänzen. Es überspringt Binärdateien (die kaum durchsucht werden) und steigert so die Effizienz. Dann gehen wir, grep -rIns ...was akustisch gut spielt :)
blutiger
2

Es funktioniert für den gleichen Zweck, aber ohne --includeOption. Es funktioniert auch auf grep 2.5.1.

grep -v -E ".*\.(html|htm|php)"
Kohei Mikami
quelle
0

Verwenden Sie grepmit findBefehl

find /some/path -name '*.html' -o -name '*.htm' -o -name '*.php' -type f 
 -exec grep PATTERN {} \+

Sie können -regexund -regextypeOptionen auch verwenden.

Prinz John Wesley
quelle