Was ist effizienter, um herauszufinden, welche Dateien in einem gesamten Dateisystem einen String enthalten: rekursives grep oder find with grep in einer exec-Anweisung? Ich nehme an, find wäre effizienter, weil Sie zumindest ein bisschen filtern können, wenn Sie die Dateierweiterung oder eine Regex kennen, die dem Dateinamen entspricht, aber wenn Sie nur wissen, -type f
welche besser ist? 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' {} \;
-exec {} +
Formular weniger Gabeln enthält und daher schneller sein sollte als-exec {} \;
. Möglicherweise müssen Sie den Optionen ein-H
(oder-h
) hinzufügengrep
, um eine genau gleichwertige Ausgabe zu erhalten.-r
Optiongrep
für die zweiteAntworten:
Ich bin mir nicht sicher:
ist wirklich das, was du meintest. Das würde bedeuten, dass alle nicht ausgeblendeten Dateien und Verzeichnisse rekursiv mit grep versehen werden
/
(aber immer noch in ausgeblendeten Dateien und Verzeichnissen nachsehen).Angenommen, Sie meinten:
Ein paar Dinge zu beachten:
grep
Implementierungen werden unterstützt-r
. Und unter denen, die dies tun, unterscheiden sich die Verhaltensweisen: Einige folgen beim Durchlaufen des Verzeichnisbaums Symlinks zu Verzeichnissen (was bedeutet, dass Sie möglicherweise mehrmals in derselben Datei suchen oder sogar in Endlosschleifen ausgeführt werden), andere nicht. Einige schauen in Gerätedateien (und es wird/dev/zero
zum Beispiel einige Zeit in Anspruch nehmen) oder Pipes oder Binärdateien ..., andere nicht.grep
beginnt, Dateien zu durchsuchen, sobald es sie entdeckt. Aber während es in einer Datei aussieht, sucht es nicht mehr nach weiteren Dateien, in denen gesucht werden kann (was in den meisten Fällen wahrscheinlich genauso gut ist).Ihre:
(Entfernt das,
-r
was hier keinen Sinn machte) ist schrecklich ineffizient, weil Sie einsgrep
pro Datei ausführen.;
sollte nur für Befehle verwendet werden, die nur ein Argument akzeptieren. Außerdem wird hiergrep
der Dateiname nicht gedruckt , da nur in einer Datei gesucht wird, sodass Sie nicht wissen, wo die Übereinstimmungen sind.Sie suchen nicht in Gerätedateien, Pipes, Symlinks ..., Sie folgen keinen Symlinks, aber Sie suchen möglicherweise immer noch in Dingen wie
/proc/mem
.wäre viel besser, weil so wenig
grep
Befehle wie möglich ausgeführt würden. Sie würden den Dateinamen erhalten, es sei denn, der letzte Lauf hat nur eine Datei. Dafür ist es besser zu verwenden:oder mit GNU
grep
:Beachten Sie, dass der
grep
Vorgang erst gestartet wird, wennfind
genügend Dateien zum Kauen gefunden wurden, sodass es zu einer anfänglichen Verzögerung kommt. Undfind
wird nicht weiter nach weiteren Dateien suchen, bis die vorherigegrep
zurückgekehrt ist. Das Zuweisen und Weitergeben der großen Dateiliste hat einige (wahrscheinlich zu vernachlässigende) Auswirkungen. Alles in allem wird es also wahrscheinlich weniger effizient sein als eingrep -r
, das nicht dem Symlink folgt oder nicht in Geräte hineinschaut.Mit GNU-Tools:
Wie oben beschrieben, werden so wenige
grep
Instanzen wie möglich ausgeführt, esfind
wird jedoch weiterhin nach weiteren Dateien gesucht, während der erstegrep
Aufruf im ersten Stapel ausgeführt wird. Das kann ein Vorteil sein oder auch nicht. Wenn beispielsweise Daten auf rotierenden Festplatten gespeichert sindfind
undgrep
auf Daten zugegriffen wird, die an verschiedenen Stellen auf der Platte gespeichert sind, wird der Plattendurchsatz verlangsamt, indem der Plattenkopf sich ständig bewegt. In einem RAID - Setup (wofind
undgrep
verschiedene Datenträger zugreifen kann) oder auf SSDs, das könnte einen positiven Unterschied machen.In einem RAID-Setup können durch Ausführen mehrerer gleichzeitiger
grep
Aufrufe ebenfalls Verbesserungen erzielt werden. Immer noch mit GNU-Tools auf RAID1-Speicher mit 3 Festplatten,könnte die Leistung erheblich steigern. Beachten Sie jedoch, dass der zweite Befehl
grep
erst gestartet wird, wenn genügend Dateien gefunden wurden, um den erstengrep
Befehl auszufüllen . Sie können eine-n
Option hinzufügenxargs
, damit dies früher geschieht (und weniger Dateien progrep
Aufruf übergeben werden).Beachten Sie auch, dass, wenn Sie die
xargs
Ausgabe an etwas anderes als ein Endgerät umleiten , diegreps
s beginnen, ihre Ausgabe zu puffern, was bedeutet, dass die Ausgabe diesergrep
s wahrscheinlich falsch verschachtelt wird. Sie müssten sie verwendenstdbuf -oL
(wo verfügbar wie unter GNU oder FreeBSD), um das zu umgehen (Sie haben möglicherweise immer noch Probleme mit sehr langen Zeilen (normalerweise> 4 KB)), oder jeder muss seine Ausgabe in eine separate Datei schreiben und diese verketten alles am Ende.Hier ist die Zeichenfolge, nach der Sie suchen, fest (kein regulärer Ausdruck), daher kann die Verwendung der
-F
Option einen Unterschied bewirken (es ist unwahrscheinlich, dassgrep
Implementierungen bereits wissen, wie sie dies optimieren können).Eine andere Sache, die einen großen Unterschied machen könnte, ist das Fixieren des Gebietsschemas auf C, wenn Sie sich in einem Mehrbyte-Gebietsschema befinden:
Um einen Blick hinein zu vermeiden
/proc
,/sys
... verwenden Sie-xdev
die Dateisysteme, in denen Sie suchen möchten , und geben Sie sie an:Oder kürzen Sie die Pfade, die Sie explizit ausschließen möchten:
quelle
-exec
Prädikats in der Solaris-ManpageWenn die
*
in demgrep
Aufruf an Sie nicht wichtig ist , dann sollte die erste als nur eine Instanz effizientergrep
gestartet und Gabeln sind nicht frei. In den meisten Fällen wird es sogar mit dem schneller sein,*
aber in Randfällen könnte die Sortierung das umkehren.Es kann auch andere sein
find
-grep
Strukturen , die vor allem mit Dateien vielen kleinen besser funktionieren. Das gleichzeitige Lesen einer großen Anzahl von Dateieinträgen und Inodes kann zu einer Leistungsverbesserung bei rotierenden Medien führen.Aber schauen wir uns die Syscall-Statistiken an:
finden
grep nur
quelle
-r
Flag von entfernen,grep
wenn Sie verwendenfind
. Sie können feststellen, dass immer wieder dieselben Dateien durchsucht wurden, indem Sie deren Anzahl vergleichenopen
.-r
sollte harmlos sein, da die-type f
Garantien keines der Argumente Verzeichnisse sind. Die Mehrfachnennungenopen()
sind eher auf die anderen Dateien zurückzuführen, diegrep
bei jedem Aufruf geöffnet wurden (Bibliotheken, Lokalisierungsdaten ...) (danke für die Bearbeitung meiner Antwort übrigens)Wenn Sie sich auf einer SSD befinden und die Suchzeit vernachlässigbar ist, können Sie GNU parallel verwenden:
Dadurch werden bis zu 8 grep-Prozesse gleichzeitig ausgeführt, je nachdem, was
find
gefunden wurde.Dies wird ein Festplattenlaufwerk zerstören, aber eine SSD sollte ziemlich gut damit zurechtkommen.
quelle
Eine weitere Sache, die Sie in diesem Fall beachten sollten, ist folgende.
Enthält eines der Verzeichnisse, die grep rekursiv durchlaufen muss, mehr Dateien als die Dateieinstellung Ihres Systems ? (zB Anzahl offener Datei-Handles, Standard ist 1024 bei den meisten Linux-Distributionen)
Wenn ja, dann ist find definitiv der richtige Weg, da bestimmte Versionen von grep mit einem zu langen Fehler bombardiert werden, wenn ein Verzeichnis mit mehr Dateien als der maximalen Einstellung für die Handles für geöffnete Dateien gefunden wird.
Nur meine 2 ¢.
quelle
grep
bombardieren? Zumindest mit GNU grep, wenn Sie einen Pfad mit Trailing angeben/
und ihn verwenden, werden-R
Sie einfach durch die Verzeichnisse iterieren. Die Shell wird nichts erweitern, es sei denn, Sie geben Shell-Globs. In dem gegebenen Beispiel (/*
) wird also nur der Inhalt der/
Materie, nicht der Unterordner, die durch einfach aufgezählt werdengrep
, als Argument aus der Shell übergeben.