2012-03-05 23:28:16 +0000 2012-03-05 23:28:16 +0000
148
148

Wie kann man bestimmte Dateinamen mit "find" ignorieren?

Einer meiner Lieblings-BASH-Befehle ist:

find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;

, der den Inhalt aller Dateien im und unterhalb des aktuellen Verzeichnisses nach dem angegebenen SearchString durchsucht. Als Entwickler hat sich dies manchmal als nützlich erwiesen.

Aufgrund meines aktuellen Projekts und der Struktur meiner Codebasis würde ich diesen BASH-Befehl jedoch gerne noch weiter ausbauen, indem ich keine Dateien durchsuche, die sich in oder unterhalb eines Verzeichnisses befinden, das “.svn” enthält, oder alle Dateien, die mit “.html” enden

Die MAN-Seite für find hat mich allerdings etwas verwirrt. Ich habe versucht, -prune zu verwenden, und das ergab ein seltsames Verhalten. In einem Versuch, nur die .html-Seiten (für den Anfang) zu überspringen, versuchte ich:

find . -wholename './*.html' -prune -exec grep 'SearchString' {} /dev/null \;

und erhielt nicht das Verhalten, das ich mir erhoffte. Ich denke, dass ich den Sinn von -prune vielleicht nicht verstehe. Könnt ihr mir helfen?

Danke

Antworten (3)

209
209
209
2012-03-06 00:40:37 +0000

Sie können die Negationsfunktion (!) von find verwenden, um Dateien mit bestimmten Namen nicht zu finden:

find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;

Wenn also der Name auf .html endet oder irgendwo im Pfad .svn enthält, wird er nicht gefunden und das Programm exec wird nicht ausgeführt.

12
12
12
2012-03-06 13:54:15 +0000

Ich habe das gleiche Problem seit langem, und es gibt mehrere Lösungen, die in verschiedenen Situationen anwendbar sein können:

  • ack-grep ist eine Art “grep für Entwickler”, das standardmäßig Verzeichnisse der Versionskontrolle und temporäre Dateien überspringt. Die Seite man erklärt, wie man nur bestimmte Dateitypen durchsucht und wie man eigene definiert.
  • greps eigene Optionen --exclude und --exclude-dir können sehr einfach verwendet werden, um Dateien globb und einzelne Verzeichnisse zu überspringen (leider kein globbing für Verzeichnisse).
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -prune -o -print0 | xargs -0 grep ... sollte funktionieren, aber die obigen Optionen sind auf Dauer wahrscheinlich weniger mühsam.
9
9
9
2012-03-06 03:29:21 +0000

Der folgende Befehl find schneidet Verzeichnisse aus, deren Namen .svn enthalten, Obwohl er nicht in das Verzeichnis hinabsteigt, wird der ausgeschnittene Pfadname gedruckt …(-name '*.svn' ist die Ursache!) …

Sie können die Verzeichnisnamen über ausfiltern: grep -d skip, das solche eingegebenen “Verzeichnisnamen” stillschweigend überspringt.

Mit GNU grep können Sie -H anstelle von /dev/null verwenden. Als kleiner Nebenaspekt: kann viel schneller sein als `\;`, z.B. für 1 Million einzeilige Dateien dauerte es mit `\;` _4m20s_, mit nur 1.2s.

Die folgende Methode verwendet xargs anstelle von -exec und geht davon aus, dass keine Zeilenumbrüche \n in Ihren Datei-Namen enthalten sind. So wie es hier verwendet wird, ist xargs fast dasselbe wie “ von find.

xargs kann Dateinamen übergeben, die aufeinanderfolgende Leerzeichen enthalten, indem das Eingabetrennzeichen mit der Option '\n' auf -d geändert wird.

Dies schließt Verzeichnisse aus, deren Namen .svn enthalten, und durchsucht nur Dateien, die nicht mit .html enden.

find . \( -name '*.svn*' -prune -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'