Was ist effizienter, um herauszufinden, welche Dateien in einem gesamten Dateisystem eine Zeichenfolge enthalten: rekursives grep oder find mit grep in einer exec-Anweisung? Ich gehe davon aus, dass find effizienter ist, da Sie zumindest etwas filtern können, wenn Sie die Dateierweiterung oder einen regulären Ausdruck kennen, der mit dem Dateinamen übereinstimmt, aber wenn Sie nur -type f kennen, was 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" {} \;

Kommentare

  • Mathematik / Informatik / Algorithmus Effizienz in ‚ t Meinung basierend.
  • Überprüfen Sie diese. Obwohl nicht rekursiv, würde es ein Verständnis geben, welches besser ist. unix.stackexchange.com/questions/47983/…
  • @AvinashRaj he ‚ fragt nicht nach einer Meinung. Er ‚ ‚ fragt, was effizienter und / oder schneller ist. nicht welches ist “ besser „. Dies ist eine perfekt beantwortbare Frage mit einer einzigen, spezifischen Antwort, die davon abhängt, wie diese beiden Programme ihre Arbeit erledigen und was genau Sie ihnen zum Durchsuchen geben.
  • Beachten Sie, dass die -exec {} + form macht weniger Gabeln und sollte daher schneller sein als -exec {} \;. Möglicherweise müssen Sie -H (oder -h) zu den grep -Optionen hinzufügen, um genau zu erhalten äquivalente Ausgabe.
  • Sie wollten wahrscheinlich nicht ‚ die Option -r für grep für die zweite

Antwort

Ich bin mir nicht sicher:

grep -r -i "the brown dog" /* 

ist wirklich das, was Sie gemeint haben. Das würde grep rekursiv bedeuten Alle nicht versteckten Dateien und Verzeichnisse in / (aber schauen Sie immer noch in versteckte Dateien und Verzeichnisse in diesen).

Angenommen, Sie meinten:

grep -r -i "the brown dog" / 

Einige Dinge zu beachten:

  • Nicht alle grep -Implementierungen unterstützen -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 se suchen Einige Male in derselben Datei oder sogar in Endlosschleifen ausgeführt), werden einige nicht. Einige schauen in Gerätedateien (und es wird einige Zeit dauern, zum Beispiel in /dev/zero) oder Pipes oder Binärdateien …, andere nicht.
  • Es ist effizient, da grep beginnt, in Dateien zu suchen, sobald es sie entdeckt. Während es in einer Datei sucht, sucht es nicht mehr nach weiteren Dateien, in denen gesucht werden kann (welche) ist wahrscheinlich in den meisten Fällen genauso gut)

Ihr:

find / -type f -exec grep -i "the brown dog" {} \; 

(, was hier keinen Sinn ergab) ist schrecklich ineffizient, weil Sie eine grep pro Datei ausführen. ; sollte nur für Befehle verwendet werden, die nur ein Argument akzeptieren. Da grep nur in einer Datei angezeigt wird, wird der Dateiname hier nicht gedruckt, sodass Sie nicht wissen, wo die Übereinstimmungen sind.

Sie “ Wenn Sie nicht in Gerätedateien, Pipes, Symlinks … schauen, folgen Sie 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, da so wenige grep -Befehle wie möglich ausgeführt würden. Sie würden den Dateinamen erhalten, es sei denn, der letzte Lauf enthält nur eine Datei. Dazu ist es besser, Folgendes zu verwenden:

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 erst mit find hat genügend Dateien zum Kauen gefunden, sodass es zu einer anfänglichen Verzögerung kommt. Und find sucht erst nach weiteren Dateien, wenn die vorherige grep zurückgekehrt ist. Das Zuweisen und Übergeben der Liste der großen Dateien hat einige (wahrscheinlich vernachlässigbare) Auswirkungen. Alles in allem wird es wahrscheinlich weniger effizient sein als ein grep -r, das keinem Symlink oder Look folgt in Geräten.

Mit GNU-Tools:

find / -type f -print0 | xargs -r0 grep -Hi "the brown dog" 

Wie oben, nur wenige grep Instanzen wie möglich werden ausgeführt, aber find sucht weiterhin nach weiteren Dateien, während der erste grep -Aufruf innerhalb des ersten Stapels erfolgt. Das kann jedoch ein Vorteil sein oder auch nicht.Wenn beispielsweise Daten auf rotierenden Festplatten gespeichert sind, verlangsamen find und grep den Zugriff auf Daten, die an verschiedenen Orten auf der Festplatte gespeichert sind, die Festplatte Durchsatz, indem der Plattenkopf ständig bewegt wird. In einem RAID-Setup (wobei find und grep auf verschiedene Festplatten zugreifen können) oder auf SSDs kann dies einen positiven Unterschied bewirken. P. >

In einem RAID-Setup kann das Ausführen mehrerer gleichzeitiger grep -Aufrufe ebenfalls Verbesserungen bewirken. Bei GNU-Tools auf RAID1-Speicher mit 3 Festplatten kann

find / -type f -print0 | xargs -r0 -P2 grep -Hi "the brown dog" 

die Leistung erheblich steigern. Beachten Sie jedoch, dass der zweite grep erst gestartet wird, wenn genügend Dateien gefunden wurden, um den ersten grep -Befehl auszufüllen. Sie können xargs eine Option -n hinzufügen, damit dies früher geschieht (und weniger Dateien pro grep Aufruf).

Beachten Sie auch, dass, wenn Sie die xargs Ausgabe auf etwas anderes als ein Endgerät umleiten, die greps s beginnen mit der Pufferung ihrer Ausgabe, was bedeutet, dass die Ausgabe dieser grep s wahrscheinlich falsch verschachtelt ist. Sie müssten (sofern verfügbar wie bei GNU oder FreeBSD), um dies zu umgehen (möglicherweise haben Sie immer noch Probleme mit sehr langen Zeilen (normalerweise> 4 KB)) oder lassen Sie ihre Ausgabe in eine separate Datei schreiben und alle verketten am Ende.

Hier ist der gesuchte String fest (kein regulärer Ausdruck), sodass die Verwendung der Option -F einen Unterschied machen kann (unwahrscheinlich als grep Implementierungen wissen, wie man das bereits optimiert).

Eine andere Sache, die koppelt Es würde einen großen Unterschied machen, das Gebietsschema auf C zu fixieren, wenn Sie sich in einem Mehrbyte-Gebietsschema befinden:

find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi "the brown dog" 

Um zu vermeiden, in , /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 beschneiden Sie die Pfade, die Sie explizit 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 {} + 

Kommentare

  • Ich ‚ nehme nicht an, dass mich jemand auf eine Ressource verweisen oder erklären kann, was {} und + bedeuten. Es gibt ‚ nichts, was ich in den Manpages für exec, grep oder find auf der Solaris-Box sehen kann, die ich ‚ verwende. Verkettet nur die Shell Dateinamen und übergibt sie an grep?
  • @Poldie, das ‚ wird in der Beschreibung von Prädikat in der Solaris-Manpage
  • Ah, ja. ‚ konnte sich bei der Suche in der Manpage nicht meinem {char entziehen. Ihr Link ist besser; Ich finde Manpages schrecklich zu lesen.
  • RAID1 mit 3 Festplatten? Wie seltsam …
  • @tink, ja, RAID1 befindet sich auf 2 oder mehr Festplatten. Mit 3 Festplatten im Vergleich zu 2 Festplatten erhöhen Sie die Redundanz und Leseleistung, während die Schreibleistung in etwa gleich ist. Mit 3 Festplatten im Gegensatz zu 2 können Sie auch Fehler korrigieren. Wenn ein Bit auf einer der Kopien umgedreht wird, können Sie ‚ feststellen, welche richtig ist, indem Sie alle überprüfen 3 Kopien, während Sie mit 2 Festplatten ‚ nicht wirklich sagen können.

Antwort

Wenn die * im grep -Aufruf für Sie nicht wichtig ist, sollte die erste als einzige effizienter sein Die Instanz von grep wird gestartet, und Gabeln sind nicht frei. In den meisten Fällen ist sie sogar mit * schneller, jedoch in Randfällen Die Sortierung könnte dies umkehren.

Möglicherweise gibt es andere findgrep Strukturen, die insbesondere bei vielen kleinen Strukturen besser funktionieren Das gleichzeitige Lesen großer Mengen von Dateieinträgen und Inodes kann zu einer Leistungsverbesserung bei rotierenden Medien führen.

Schauen wir uns jedoch die Syscall-Statistiken an:

find

> strace -cf find . -type f -exec grep -i -r "the brown dog" {} \; % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 97.86 0.883000 3619 244 wait4 0.53 0.004809 1 9318 4658 open 0.46 0.004165 1 6875 mmap 0.28 0.002555 3 977 732 execve 0.19 0.001677 2 980 735 stat 0.15 0.001366 1 1966 mprotect 0.09 0.000837 0 1820 read 0.09 0.000784 0 5647 close 0.07 0.000604 0 5215 fstat 0.06 0.000537 1 493 munmap 0.05 0.000465 2 244 clone 0.04 0.000356 1 245 245 access 0.03 0.000287 2 134 newfstatat 0.03 0.000235 1 312 openat 0.02 0.000193 0 743 brk 0.01 0.000082 0 245 arch_prctl 0.01 0.000050 0 134 getdents 0.00 0.000045 0 245 futex 0.00 0.000041 0 491 rt_sigaction 0.00 0.000041 0 246 getrlimit 0.00 0.000040 0 489 244 ioctl 0.00 0.000038 0 591 fcntl 0.00 0.000028 0 204 188 lseek 0.00 0.000024 0 489 set_robust_list 0.00 0.000013 0 245 rt_sigprocmask 0.00 0.000012 0 245 set_tid_address 0.00 0.000000 0 1 uname 0.00 0.000000 0 245 fchdir 0.00 0.000000 0 2 1 statfs ------ ----------- ----------- --------- --------- ---------------- 100.00 0.902284 39085 6803 total 

nur grep

> strace -cf grep -r -i "the brown dog" . % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 40.00 0.000304 2 134 getdents 31.71 0.000241 0 533 read 18.82 0.000143 0 319 6 openat 4.08 0.000031 4 8 mprotect 3.29 0.000025 0 199 193 lseek 2.11 0.000016 0 401 close 0.00 0.000000 0 38 19 open 0.00 0.000000 0 6 3 stat 0.00 0.000000 0 333 fstat 0.00 0.000000 0 32 mmap 0.00 0.000000 0 4 munmap 0.00 0.000000 0 6 brk 0.00 0.000000 0 2 rt_sigaction 0.00 0.000000 0 1 rt_sigprocmask 0.00 0.000000 0 245 244 ioctl 0.00 0.000000 0 1 1 access 0.00 0.000000 0 1 execve 0.00 0.000000 0 471 fcntl 0.00 0.000000 0 1 getrlimit 0.00 0.000000 0 1 arch_prctl 0.00 0.000000 0 1 futex 0.00 0.000000 0 1 set_tid_address 0.00 0.000000 0 132 newfstatat 0.00 0.000000 0 1 set_robust_list ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000760 2871 466 total 

Kommentare

  • Auf der Skala der Suche in einem gesamten Dateisystem sind Gabeln vernachlässigbar. E / A ist das, was Sie reduzieren möchten.
  • Obwohl es sich um einen Fehler aus dem OP handelt, ist der Vergleich falsch. Sie sollten das Flag -r von grep bei Verwendung von find. Sie können sehen, dass immer wieder dieselben Dateien durchsucht wurden, indem Sie die Anzahl der open, die passiert sind, vergleichen.
  • @qwertzguy, nein, die -r sollte harmlos sein, da die -type f garantiert, dass keines der Argumente Verzeichnisse sind. Die mehreren open() s sind eher auf die anderen Dateien zurückzuführen, die bei jedem Aufruf von grep geöffnet wurden (Bibliotheken, Lokalisierungsdaten …) ( danke für die Bearbeitung meiner Antwort übrigens)

Antwort

Wenn Sie auf einer SSD sind und Zeit suchen Ist dies vernachlässigbar, können Sie GNU parallel verwenden:

find /path -type f | parallel --gnu --workdir "$PWD" -j 8 " grep -i -r "the brown dog" {} " 

Dadurch werden bis zu 8 grep-Prozesse gleichzeitig ausgeführt, basierend auf gefunden.

Dies wird ein Festplattenlaufwerk beschädigen, aber eine SSD sollte ziemlich gut damit umgehen können.

Antwort

Eine weitere Sache, die Sie in diesem Fall berücksichtigen sollten, ist folgende:

Enthält eines der Verzeichnisse, die grep rekursiv durchlaufen muss, mehr Dateien als die nofile -Einstellung Ihres Systems? (z. B. Anzahl der Handles für geöffnete Dateien, Standard ist 1024 bei den meisten Linux-Distributionen)

Wenn ja, ist find definitiv der richtige Weg, da bestimmte Versionen von grep bombardiert mit einem Argumentliste zu langen Fehler, wenn ein Verzeichnis mit mehr Dateien als der maximal geöffneten Datei aufgerufen wird behandelt die Einstellung.

Nur meine 2 ¢.

Kommentare

  • Warum sollte grep Bombe aus? Zumindest mit GNU grep, wenn Sie einen Pfad mit nachfolgendem / angeben und -R verwenden. ‚ Ich werde einfach durch die Verzeichnisse iterieren. Die Shell is ‚ wird nichts erweitern, es sei denn, Sie geben Shell-Globs. Im angegebenen Beispiel (/*) ist also nur der Inhalt von / von Bedeutung, nicht der Unterordner, die einfach durch grep, nicht als Argument von der Shell übergeben.
  • Nun, wenn man bedenkt, dass das OP nach einer rekursiven Suche gefragt hat (z. B. “ grep -r -i ‚ der braune Hund ‚ / * „) habe ich gesehen GNU ‚ s grep (mindestens Version 2.9) bombardiert mit: “ -bash: / bin / grep: Argumentliste zu lang “ unter Verwendung der genauen Suche, die das OP in einem Verzeichnis mit über 140.000 Unterverzeichnissen verwendet hat.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.