Was ist effizienter, um herauszufinden, welche Dateien in einem gesamten Dateisystem eine Zeichenfolge enthalten:rekursives grep oder suchen mit grep in einer exec-Anweisung? Ich nehme an, find wäre effizienter, weil Sie zumindest etwas filtern können, wenn Sie die Dateierweiterung oder eine Regex kennen, die zum Dateinamen passt, aber wenn Sie nur -type f
kennen Welches ist besser? GNU grep 2.6.3; find (GNU findutils) 4.4.2
Beispiel:
grep -r -i 'the brown dog' /
find / -type f -exec grep -i 'the brown dog' {} ;
Akzeptierte Antwort:
Ich bin mir nicht sicher:
grep -r -i 'the brown dog' /*
ist wirklich das, was du gemeint hast. Das würde grep rekursiv in allen nicht versteckten Dateien und Verzeichnissen in /
bedeuten (aber schauen Sie trotzdem in versteckte Dateien und Verzeichnisse darin).
Angenommen, Sie meinten:
grep -r -i 'the brown dog' /
Ein paar Dinge zu beachten:
- Nicht alle
grep
Implementierungen unterstützen-r
. Und bei denen, die dies tun, unterscheidet sich das Verhalten:Einige folgen symbolischen Links zu Verzeichnissen, wenn sie den Verzeichnisbaum durchlaufen (was bedeutet, dass Sie möglicherweise mehrmals in derselben Datei suchen oder sogar in Endlosschleifen laufen), andere nicht. Einige werden in Gerätedateien nachsehen (und es wird einige Zeit in/dev/zero
dauern zum Beispiel) oder Pipes oder Binärdateien…, manche nicht. - Effizient wie
grep
beginnt, in Dateien zu suchen, sobald es sie entdeckt. Aber während es in einer Datei sucht, sucht es nicht mehr nach weiteren Dateien, in denen es suchen kann (was in den meisten Fällen wahrscheinlich genauso gut ist)
Ihr:
find / -type f -exec grep -i 'the brown dog' {} ;
(-r
entfernt was hier keinen Sinn machte) ist schrecklich ineffizient, weil Sie ein grep
ausführen pro Datei. ;
sollte nur für Befehle verwendet werden, die nur ein Argument akzeptieren. Außerdem hier, weil grep
sucht nur in einer Datei, der Dateiname wird nicht gedruckt, sodass Sie nicht wissen, wo die Übereinstimmungen sind.
Sie schauen nicht in Gerätedateien, Pipes, Symlinks …, Sie folgen keinen Symlinks, aber Sie schauen möglicherweise immer noch in Dinge wie /proc/mem
.
find / -type f -exec grep -i 'the brown dog' {} +
wäre viel besser, weil so wenig grep
Befehle wie möglich ausgeführt werden. Sie erhalten den Dateinamen, es sei denn, der letzte Lauf hat nur eine Datei. Verwenden Sie dafür besser:
find / -type f -exec grep -i 'the brown dog' /dev/null {} +
oder mit GNU grep
:
find / -type f -exec grep -Hi 'the brown dog' {} +
Beachten Sie, dass grep
wird erst mit find
gestartet hat genug Dateien gefunden, um darauf herumzukauen, also wird es eine anfängliche Verzögerung geben. Und find
wird bis zum vorherigen grep
nicht weiter nach weiteren Dateien suchen ist zurückgekommen. Das Zuweisen und Weitergeben der großen Dateiliste hat einige (wahrscheinlich vernachlässigbare) Auswirkungen, also wird es insgesamt wahrscheinlich weniger effizient sein als ein grep -r
die keinem Symlink folgt oder in Geräte hineinschaut.
Mit GNU-Tools:
find / -type f -print0 | xargs -r0 grep -Hi 'the brown dog'
Wie oben, so wenig grep
Instanzen wie möglich werden ausgeführt, aber find
wird weiter nach weiteren Dateien suchen, während das erste grep
Der Aufruf sucht im ersten Batch. Das kann ein Vorteil sein oder auch nicht. Beispiel:Bei Daten, die auf Rotationsfestplatten gespeichert sind, find
und grep
Der Zugriff auf Daten, die an verschiedenen Orten auf der Festplatte gespeichert sind, verlangsamt den Festplattendurchsatz, da sich der Festplattenkopf ständig bewegt. In einem RAID-Setup (wo find
und grep
kann auf verschiedene Festplatten zugreifen) oder auf SSDs, das könnte einen positiven Unterschied machen.
In einem RAID-Setup mehrere gleichzeitig ausführen grep
Anrufungen könnten auch die Dinge verbessern. Immer noch mit GNU-Tools auf RAID1-Speicher mit 3 Festplatten,
find / -type f -print0 | xargs -r0 -P2 grep -Hi 'the brown dog'
kann die Leistung erheblich steigern. Beachten Sie jedoch, dass das zweite grep
wird erst gestartet, wenn genügend Dateien gefunden wurden, um das erste grep
zu füllen Befehl. Sie können ein -n
hinzufügen Option zu xargs
damit dies früher geschieht (und weniger Dateien pro grep
übergeben werden Aufruf).
Beachten Sie auch, dass Sie beim Umleiten von xargs
Ausgabe an etwas anderes als ein Endgerät, dann greps
s beginnen, ihre Ausgabe zu puffern, was bedeutet, dass die Ausgabe dieser grep
s werden wahrscheinlich falsch interleaved. Sie müssten stdbuf -oL
verwenden (wo verfügbar wie unter GNU oder FreeBSD) auf ihnen, um dies zu umgehen (Sie haben möglicherweise immer noch Probleme mit sehr langen Zeilen (normalerweise>4KiB)) oder lassen Sie jede ihre Ausgabe in eine separate Datei schreiben und am Ende alle verketten.
Hier ist die gesuchte Zeichenfolge festgelegt (kein regulärer Ausdruck), also verwenden Sie -F
Option einen Unterschied machen könnte (unwahrscheinlich, da grep
Implementierungen wissen das bereits zu optimieren).
Eine andere Sache, die einen großen Unterschied machen könnte, ist das Festlegen des Gebietsschemas auf C, wenn Sie sich in einem Multi-Byte-Gebietsschema befinden:
find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi 'the brown dog'
Um zu vermeiden, in /proc
zu schauen , /sys
…, verwenden Sie -xdev
und geben Sie die Dateisysteme an, in denen Sie suchen möchten:
LC_ALL=C find / /home -xdev -type f -exec grep -i 'the brown dog' /dev/null {} +
Oder löschen Sie die Pfade, die Sie ausdrücklich ausschließen möchten:
LC_ALL=C find / ( -path /dev -o -path /proc -o -path /sys ) -prune -o
-type f -exec grep -i 'the brown dog' /dev/null {} +