Ich habe beide Befehle ausprobiert und der Befehl find | grep "filename" ist um ein Vielfaches langsamer als der einfache find "filename" Befehl.

Was wäre eine richtige Erklärung für dieses Verhalten?

Kommentare

  • Sie listen jede Datei mit find auf und übergeben die Daten dann an grep, um sie zu verarbeiten. Mit dem darauf verwendeten find ‚ verpassen Sie den Schritt, jede aufgelistete Datei an grep zu übergeben, um die Ausgabe zu analysieren. Dies wird daher schneller gehen.
  • In welchem Sinne langsamer? Dauert die Ausführung der Befehle anders lange?
  • Ich kann ‚ dies nicht lokal reproduzieren. Wenn überhaupt, meldet time find "$HOME" -name '.profile' eine längere Zeit als time find "$HOME" | grep -F '.profile'. (17s vs. 12s).
  • @JenniferAnderson Ich habe beide wiederholt ausgeführt. Die 17 und 12 Sekunden sind Durchschnittswerte. Und ja, die grep -Variante stimmt mit einer beliebigen Stelle im find -Ergebnis überein, während sie mit find -name würde nur genau übereinstimmen (in diesem Fall).
  • Ja, find filename wäre schnell . Ich nahm an, dass dies ein Tippfehler war und dass das OP find -name filename bedeutete. Mit find filename wird nur filename untersucht (und sonst nichts).

Antwort

(Ich gehe hier von GNU find aus)

Verwenden Sie nur

find filename 

wäre schnell, da nur filename oder die Namen in filename, wenn es sich um ein Verzeichnis handelt, oder ein Fehler, wenn dieser Name im aktuellen Verzeichnis nicht vorhanden war. Es ist eine sehr schnelle Operation, ähnlich wie ls filename (aber rekursiv, wenn filename ein Verzeichnis ist).

In Im Gegensatz dazu würde

find | grep filename 

es find ermöglichen, eine Liste von allen Namen zu generieren Das aktuelle Verzeichnis und darunter, das dann grep filtern würde. Dies wäre offensichtlich eine viel langsamere Operation.

Ich gehe davon aus, dass es sich tatsächlich um handelt beabsichtigt war

find . -type f -name "filename" 

Dies würde nach filename als Namen einer regulären Datei irgendwo in suchen das aktuelle Verzeichnis oder darunter.

Dies ist genauso schnell (oder vergleichsweise schnell) wie find | grep filename, aber das grep Die Lösung würde filename mit dem vollständigen Pfad jedes gefundenen Namens abgleichen, ähnlich wie -path "*filename*" mit .


Die Verwirrung beruht auf einem Missverständnis darüber, wie find funktioniert.

Das Dienstprogramm verwendet eine Reihe von Pfaden und gibt alle Namen unter diesen Pfaden zurück.

Sie können dann Beschränken Sie die zurückgegebenen Namen mithilfe verschiedener Tests, die sich auf den Dateinamen, den Pfad, den Zeitstempel, die Dateigröße, den Dateityp usw. auswirken können.

Wenn Sie

find a b c 

Sie bitten find, jeden unter den drei Pfaden verfügbaren Namen aufzulisten a, b und c. Wenn dies zufällig Namen von regulären Dateien im aktuellen Verzeichnis sind, werden diese zurückgegeben. Wenn einer von ihnen zufällig der Name eines Verzeichnisses ist, wird er zusammen mit allen weiteren Namen in diesem Verzeichnis zurückgegeben.

Wenn ich

find . -type f -name "filename" 

Dies generiert eine Liste aller Namen im aktuellen Verzeichnis (.) und darunter. Dann beschränkt es die Namen auf die von regulären Dateien, d. H. Nicht Verzeichnissen usw., mit -type f. Dann gibt es eine weitere Einschränkung für Namen, die mit filename unter Verwendung von -name "filename" übereinstimmen. Die Zeichenfolge filename kann ein Dateinamen-Globbing-Muster sein, z. B. *.txt (denken Sie daran, es zu zitieren!).

Beispiel:

Im Folgenden wird die Datei mit dem Namen .profile in meinem Ausgangsverzeichnis „gefunden“:

$ pwd /home/kk $ find .profile .profile 

Tatsächlich werden jedoch nur alle Namen im Pfad .profile zurückgegeben (es gibt nur einen Namen, und dieser gehört zu dieser Datei).

Dann cd eine Ebene höher und versuche es erneut:

$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory 

Die find kann jetzt keinen Pfad mit dem Namen .profile finden.

Wenn ich jedoch das aktuelle Verzeichnis anzeigen und die zurückgegebenen Namen auf .profile beschränken soll, wird es gefunden es auch von dort:

$ pwd /home $ find . -name ".profile" ./kk/.profile 

Kommentare

  • find filename würde nur filename zurückgeben, wenn filename nicht vom Typ Verzeichnis (oder vom Typ Verzeichnis, aber hatte selbst keinen Eintrag)

Antwort

Nicht-technische Erklärung: Suche nach Jack in einer Menschenmenge ist schneller als nach allen in einer Menschenmenge zu suchen und alle außer Jack aus der Überlegung auszuschließen.

Kommentare

  • Das Problem ist, dass das OP Jack erwartet sei die einzige Person in der Menge. Wenn ja, haben sie ‚ Glück. find jack listet jack auf, wenn ‚ eine Datei mit dem Namen oder alle Namen im Verzeichnis, wenn ‚ ein Verzeichnis ist. ‚ ist ein Missverständnis darüber, wie find funktioniert.

Antwort

Ich habe das Problem noch nicht verstanden, kann aber weitere Erkenntnisse liefern.

Wie bei Kusalananda der Aufruf find | grep ist auf meinem System deutlich schneller, was wenig Sinn macht. Zuerst nahm ich eine Art Pufferproblem an; Das Schreiben in die Konsole verlangsamt die Zeit bis zum nächsten Systemaufruf zum Lesen des nächsten Dateinamens. Das Schreiben in eine Pipe ist sehr schnell: etwa 40 MB / s, selbst für 32-Byte-Schreibvorgänge (auf meinem eher langsamen System; 300 MB / s für eine Blockgröße von 1 MB). Daher habe ich angenommen, dass find beim Schreiben in eine Pipe (oder Datei) schneller aus dem Dateisystem lesen kann, sodass die beiden Vorgänge zum Lesen von Dateipfaden und zum Schreiben in die Konsole parallel ausgeführt werden können ( was find als einzelner Thread-Prozess nicht alleine tun kann.

Es ist find

Vergleichen der beiden Aufrufe

:> time find "$HOME"/ -name "*.txt" >/dev/null real 0m0.965s user 0m0.532s sys 0m0.423s 

und

:> time find "$HOME"/ >/dev/null real 0m0.653s user 0m0.242s sys 0m0.405s 

zeigt, dass find etwas unglaublich Dummes tut (was auch immer das sein mag) Es stellt sich heraus, dass die Ausführung von -name "*.txt" ziemlich inkompetent ist.

Kann vom Eingabe / Ausgabe-Verhältnis

Sie könnten denken, dass find -name gewinnt, wenn es sehr wenig zu schreiben gibt. Aber es wird nur peinlicher für find. Es verliert, auch wenn überhaupt nichts zu schreiben ist gegen 200K-Dateien (13M Pipe-Daten) für grep:

time find /usr -name lwevhewoivhol 

find kann so schnell sein wie grep, obwohl

Es stellt sich heraus, dass sich die Dummheit von find mit name nicht auf andere Tests erstreckt. Verwenden Sie stattdessen einen regulären Ausdruck, und das Problem ist behoben:

:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s 

Ich denke, dies kann als Fehler angesehen werden. Ist jemand bereit, einen Fehlerbericht einzureichen? Meine Version ist find (GNU findutils) 4.6.0

Kommentare

  • Wie wiederholbar sind Ihre Timings? Wenn Sie zuerst den Test -name durchgeführt haben, war er möglicherweise langsamer, da der Verzeichnisinhalt nicht zwischengespeichert wurde. (Beim Testen von -name und -regex stelle ich fest, dass sie ungefähr dieselbe Zeit in Anspruch nehmen, zumindest wenn der Cache-Effekt berücksichtigt wurde Natürlich kann es sich nur um eine andere Version von find …)
  • @psmears handeln. Natürlich habe ich diese Tests mehrmals durchgeführt. Das Caching-Problem wurde bereits in den Kommentaren zur Frage vor der ersten Antwort erwähnt. Meine find -Version ist find (GNU findutils) 4.6.0
  • Warum ist es überraschend, dass das Hinzufügen von -name '*.txt' langsamer wird find? Es muss zusätzliche Arbeit leisten und jeden Dateinamen testen.
  • @Barmar Einerseits kann diese zusätzliche Arbeit extrem schnell erledigt werden. Andererseits spart diese zusätzliche Arbeit andere Arbeit. find muss weniger Daten schreiben. Das Schreiben in eine Pipe ist viel langsamer.
  • Das Schreiben auf eine Festplatte ist sehr langsam. Das Schreiben in eine Pipe ist nicht so schlecht, es wird nur in einen Kernelpuffer kopiert. Beachten Sie, dass in Ihrem ersten Test beim Schreiben von mehr in /dev/null weniger Systemzeit verwendet wurde.

Antwort

Hinweis : Ich gehe davon aus, dass Sie find . -name filename (andernfalls suchen Sie nach verschiedenen Dingen; find filename untersucht tatsächlich einen Pfad namens filename , der enthält möglicherweise fast keine Dateien und wird daher sehr schnell beendet.


Angenommen, Sie haben ein Verzeichnis mit fünftausend Dateien. Auf den meisten Dateisystemen werden diese Dateien tatsächlich in einer tree -Struktur gespeichert, mit der eine bestimmte Datei schnell gefunden werden kann. P. >

Wenn Sie also find bitten, eine Datei zu suchen, deren Name nur überprüft werden muss, fragt find für diese Datei und nur diese Datei in das zugrunde liegende Dateisystem, das nur sehr wenige Seiten aus dem Massenspeicher liest. Wenn das Dateisystem also sein Geld wert ist, wird dieser Vorgang viel schneller ausgeführt als den gesamten Baum durchlaufen , um alle Einträge abzurufen.

Wenn Sie nach find fragen, aber genau das tun Sie, durchlaufen Sie den gesamten Baum und lesen. Jeder einzelne Eintrag. Mit großen Verzeichnissen, Dies könnte ein Problem sein (genau aus diesem Grund erstellen mehrere Softwareprogramme, die viele Dateien auf der Festplatte speichern müssen, „Verzeichnisbäume“ mit einer Tiefe von zwei oder drei Komponenten: Auf diese Weise muss jedes einzelne Blatt nur weniger Dateien enthalten.)

Antwort

Nehmen wir an, dass die Datei / john / paul / george / ringo / beatles existiert und die gesuchte Datei heißt „Steine“

find / stones 

find vergleicht „Beatles“ mit „Steinen“ und lässt sie fallen, wenn „s“ und „b“ nicht übereinstimmen .

find / | grep stones 

In diesem Fall wird „/ john / paul / george / ringo / beatles“ an grep und grep wil übergeben Ich muss mich durch den gesamten Pfad arbeiten, bevor ich feststellen kann, ob es eine Übereinstimmung ist.

grep erledigt daher viel mehr Arbeit, weshalb es länger dauert.

Kommentare

  • Haben Sie es versucht?
  • Die Kosten für die Zeichenfolgenvergleiche (extrem einfach und billig) werden durch die E / A-Kosten (oder nur für den Systemaufruf, wenn zwischengespeichert) vollständig in den Schatten gestellt
  • grep isn ‚ ta String-Vergleich, sein Vergleich mit regulären Ausdrücken, was bedeutet, dass er sich durch den gesamten String arbeiten muss, bis er einen findet ein Match oder erreicht das Ende. Die Verzeichnissuchen sind gleich, egal was passiert.
  • @Paranoid Hm, über welche Version von find sprechen Sie? Es ‚ ist anscheinend nichts wie das find , das ich ‚ im Debian gewohnt bin.

Schreibe einen Kommentar

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