Wie übergebe ich eine Dateiliste an grep?

98

Ich verwende findund erhalte eine Liste der Dateien, grepdurch die ich gehen möchte . Wie leite ich diese Liste weiter grep?

Arcabard
quelle

Antworten:

116

Nun, der generische Fall, der mit jedem Befehl funktioniert, der in stdout schreibt, ist die Verwendung xargs, mit der Sie eine beliebige Anzahl von Befehlszeilenargumenten an das Ende eines Befehls anhängen können:

$ find … | xargs grep 'search'

Oder um den Befehl in Ihre grepZeile mit Backticks oder einzubetten $(), wird der Befehl ausgeführt und die Ausgabe ersetzt:

$ grep 'search' $(find …)

Beachten Sie, dass diese Befehle nicht funktionieren, wenn die Dateinamen Leerzeichen oder bestimmte andere „seltsame Zeichen“ enthalten ( \'"für xargs, \[*?für $(find …)).


Im speziellen Fall findder Fähigkeit, ein Programm für die angegebenen Argumente auszuführen, ist jedoch Folgendes integriert:

$ find … -exec grep 'search' {} \;

Alles zwischen -execund ;ist der auszuführende Befehl. {}wird durch den gefundenen Dateinamen ersetzt durch find. Dadurch wird grepfür jede Datei eine separate Datei ausgeführt. da grepviele Dateinamen nehmen und suchen sie alle, können Sie die Änderung ;zu +allen zu sagen , finden Dateinamen die Anpassung an passieren grepauf einmal:

$ find … -exec grep 'search' {} \+
Michael Mrozek
quelle
1
Zu beachten ist, dass die ersten beiden Formulare nicht mit Dateinamen funktionieren, die Leerzeichen enthalten.
Enzotib
1
Ich ziehe find ... -type f -print0 | xargs -r0 grep 'search' /dev/null. QED. Obwohl -exec +es sehr effizient ist, gibt es es nicht in allen Versionen von find.
Arcege
Leider kann ich dich 3 mal nicht richtig überprüfen.
Arcabard,
3
Ich schlage vor, die -execanstelle der zu verwenden xargs. Wenn Sie das -execin verwenden find, wird nur eine Shell erstellt, um nach dem Inhalt zu suchen . Wenn Sie die verwenden xargs, werden zwei Schalen erstellt: eine für die findund die andere für die xargs.
2
Durch Experimente finde ich, dass die $ find … -exec grep 'search' {} \+Form viel schneller ist.
Gogoud
9

Einige Versionen von grep(z. B. unter nicht eingebettetem Linux, BSD oder Mac OS X) -rbieten die Möglichkeit einer rekursiven Suche. Verwenden Sie unter OpenBSD -R(und es gibt keine --excludewie im folgenden Beispiel). Dies umfasst einfache Kombinationen von findmit grep.

Wenn Ihre Implementierung nicht über das -RFlag verfügt oder wenn Sie schickere Dateizuordnungskriterien wünschen, können Sie das -execprimäre von verwenden find, um die Ausführung zu veranlassen grep. Einige ältere findImplementierungen unterstützen nicht -exec+; Verwenden Sie auf diesen Systemen a ;anstelle von a +(dies wird grepeinmal pro Datei aufgerufen , ist also langsamer, aber ansonsten ist das Ergebnis dasselbe). Beachten Sie den /dev/nullTrick, der bewirkt grep, dass der Dateiname auch dann angezeigt wird, wenn er zufällig für eine einzelne Datei aufgerufen wird (GNU grep und FreeBSD / NetBSD / OSX grep haben die -HOption, denselben Effekt zu erzielen).

find . -type f -name '*.o' -prune -o -exec grep 'needle' /dev/null {} +
grep -r --exclude='*.o' 'needle' .
Gilles
quelle
2
GNU grephat die -HOption, den Dateinamen immer zu drucken.
Enzotib