Ich habe beide Befehle ausprobiert und der Befehl find | grep 'filename'
ist viele Male langsamer als der einfache find 'filename'
Befehl.
Was wäre eine richtige Erklärung für dieses Verhalten?
command-line
grep
find
search
file-search
yoyo_fun
quelle
quelle
time find "$HOME" -name '.profile'
meldet sich eine längere Zeit alstime find "$HOME" | grep -F '.profile'
. (17s gegen 12s).grep
Variation stimmt überall imfind
Ergebnis überein , wohingegen die Übereinstimmung mitfind -name
nur genau übereinstimmen würde (in diesem Fall).find filename
wäre schnell . Ich nahm irgendwie an, dass dies ein Tippfehler war und dass das OP bedeutetefind -name filename
. Mitfind filename
nurfilename
würde untersucht (und sonst nichts).Antworten:
(Ich gehe hier von GNU
find
aus)Mit just
wäre schnell, weil es nur zurückkehren würde
filename
, oder die Namen darin,filename
wenn es ein Verzeichnis ist, oder ein Fehler, wenn dieser Name nicht im aktuellen Verzeichnis vorhanden wäre. Es ist eine sehr schnelle Operation, ähnlich wiels filename
(aber rekursiv, wennfilename
es sich um ein Verzeichnis handelt).Im Gegensatz,
würde es ermöglichen
find
, eine Liste aller Namen aus dem aktuellen Verzeichnis und darunter zu generieren , diegrep
dann filtern würde. Dies wäre offensichtlich eine viel langsamere Operation.Ich gehe davon aus, dass das, was eigentlich beabsichtigt war, war
Dies würde
filename
als Name einer regulären Datei irgendwo im aktuellen Verzeichnis oder darunter suchen .Dies ist so schnell (oder vergleichsweise schnell) wie
find | grep filename
, aber diegrep
Lösung würde mitfilename
dem vollständigen Pfad jedes gefundenen Namens übereinstimmen , ähnlich wie dies der Fall-path '*filename*'
wärefind
.Die Verwirrung rührt von einem Missverständnis darüber her, wie es
find
funktioniert.Das Dienstprogramm verwendet eine Reihe von Pfaden und gibt alle Namen unter diesen Pfaden zurück.
Sie können dann die zurückgegebenen Namen mithilfe verschiedener Tests einschränken, die sich auf den Dateinamen, den Pfad, den Zeitstempel, die Dateigröße, den Dateityp usw. auswirken können.
Wenn du sagst
Sie fragen
find
jeden Namen unter den drei Wege zur Listea
,b
undc
. 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 es tue
Dadurch wird eine Liste aller Namen im aktuellen Verzeichnis (
.
) und darunter generiert . Dann beschränkt es die Namen auf die von regulären Dateien, dh nicht auf Verzeichnisse usw., mit-type f
. Dann gibt es eine weitere Einschränkung für Namen, die mitfilename
using übereinstimmen-name 'filename'
. Die Zeichenfolgefilename
kann ein Dateinamen-Globbing-Muster sein, z. B.*.txt
(denken Sie daran, es zu zitieren!).Beispiel:
Folgendes scheint die
.profile
in meinem Home-Verzeichnis aufgerufene Datei zu "finden" :Tatsächlich werden jedoch nur alle Namen im Pfad zurückgegeben
.profile
(es gibt nur einen Namen, und das ist von dieser Datei).Dann steige ich
cd
eine Ebene höher und versuche es erneut:Der
find
Befehl kann jetzt keinen aufgerufenen Pfad finden.profile
.Wenn ich es jedoch dazu bringe, das aktuelle Verzeichnis zu betrachten und dann die zurückgegebenen Namen auf nur zu beschränken
.profile
, findet es es auch von dort:quelle
find filename
würde nur zurückkehren,filename
wennfilename
es nicht vom Typ Verzeichnis war (oder vom Typ Verzeichnis war, aber selbst keinen Eintrag hatte)Nicht-technische Erklärung: Die Suche nach Jack in einer Menschenmenge ist schneller als die Suche nach allen in einer Menschenmenge und die Beseitigung aller außer Jack.
quelle
find jack
listet auf,jack
ob es sich um eine aufgerufene Datei handeltjack
, oder alle Namen im Verzeichnis, wenn es sich um ein Verzeichnis handelt. Es ist ein Missverständnis darüber, wie esfind
funktioniert.Ich habe das Problem noch nicht verstanden, kann aber weitere Erkenntnisse liefern.
Wie bei Kusalananda ist der
find | grep
Anruf 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, dassfind
beim Schreiben in eine Pipe (oder Datei) schneller aus dem Dateisystem gelesen werden kann, sodass die beiden Vorgänge zum Lesen von Dateipfaden und zum Schreiben in die Konsole parallel ausgeführt werden können (wasfind
als einzelner Thread-Prozess nicht alleine möglich ist.Es ist
find
‚s FehlerVergleich der beiden Anrufe
und
zeigt, dass
find
etwas unglaublich Dummes tut (was auch immer das sein mag). Es stellt sich einfach als ziemlich inkompetent bei der Ausführung heraus-name '*.txt'
.Kann vom Input / Output-Verhältnis abhängen
Sie könnten denken, dass
find -name
gewinnt, wenn es sehr wenig zu schreiben gibt. Aber es wird nur peinlicherfind
. Es verliert auch dann, wenn für 200K-Dateien (13M Pipe-Daten) überhaupt nichts zu schreiben ist fürgrep
:find
kann so schnell wie seingrep
obwohl,Es stellt sich heraus, dass sich
find
die Dummheit mitname
nicht auf andere Tests erstreckt. Verwenden Sie stattdessen einen regulären Ausdruck und das Problem ist behoben:Ich denke, das kann als Fehler angesehen werden. Ist jemand bereit, einen Fehlerbericht einzureichen? Meine Version ist find (GNU findutils) 4.6.0
quelle
-name
Test zuerst durchgeführt haben, war er möglicherweise langsamer, da der Verzeichnisinhalt nicht zwischengespeichert wurde. (Beim Testen-name
und-regex
ich finde, dass sie ungefähr die gleiche Zeit in Anspruch nehmen, zumindest wenn der Cache-Effekt berücksichtigt wurde. Natürlich kann es sich nur um eine andere Version vonfind
... handeln)find
Version ist find (GNU findutils) 4.6.0-name '*.txt'
langsamer wirdfind
? Es muss zusätzliche Arbeit leisten und jeden Dateinamen testen.find
muss weniger Daten schreiben. Und das Schreiben in eine Pipe ist viel langsamer./dev/null
irgendwie weniger Systemzeit zu verbrauchen .Hinweis : Ich gehe davon aus, dass Sie meinen
find . -name filename
(ansonsten suchen Sie nach verschiedenen Dingen; untersuchtfind filename
tatsächlich einen Pfad namens Dateiname , der möglicherweise fast keine Dateien enthält und daher sehr schnell beendet wird).Angenommen, Sie haben ein Verzeichnis mit fünftausend Dateien. Bei den meisten Dateisystemen werden diese Dateien tatsächlich in einer gespeicherten Baumstruktur , die schnell ermöglicht es jedem , einen suchen angegebene Datei.
Wenn Sie also
find
nach einer Datei suchen, deren Name nur überprüft werden muss,find
werden Sie nach dieser Datei und nur nach dieser Datei im zugrunde liegenden Dateisystem gefragt , das nur sehr wenige Seiten aus dem Massenspeicher liest. Wenn das Dateisystem also das Geld wert ist, wird dieser Vorgang viel schneller ausgeführt als das Durchlaufen des gesamten Baums , um alle Einträge abzurufen.Wenn Sie nach einer Ebene fragen,
find
aber genau das tun Sie, durchqueren Sie den gesamten Baum und lesen. Jeder. Single. Eintrag. Bei großen Verzeichnissen kann dies ein Problem sein (genau aus diesem Grund erstellen mehrere Softwareprogramme, die viele Dateien auf der Festplatte speichern müssen, zwei oder drei Komponenten tiefe "Verzeichnisbäume": Auf diese Weise muss jedes einzelne Blatt nur weniger enthalten Dateien).quelle
Nehmen wir an, die Datei / john / paul / george / ringo / beatles existiert und die gesuchte Datei heißt "Steine".
find vergleicht 'Beatles' mit 'Steinen' und lässt es fallen, wenn 's' und 'b' nicht übereinstimmen.
In diesem Fall wird find '/ john / paul / george / ringo / beatles' an grep übergeben und grep muss sich durch den gesamten Pfad arbeiten, bevor festgestellt wird, ob es eine Übereinstimmung ist.
grep macht deshalb viel mehr arbeit, weshalb es länger dauert
quelle