Am încercat ambele comenzi, iar comanda find | grep "filename"
este de multe ori mai lentă decât simpla .
Care ar fi o explicație adecvată pentru acest comportament?
Comentarii
- Tu listează fiecare fișier cu găsire și apoi transferă datele către grep pentru procesare. Cu find folosit pe ‘ propriile dvs. lipsește pasul de a trece fiecare fișier listat la grep pentru a analiza ieșirea. Prin urmare, acest lucru va fi mai rapid.
- Mai lent în ce sens? Comenzile durează un timp diferit pentru a fi finalizate?
- Nu pot ‘ să reproduc acest lucru local. Dacă este ceva,
time find "$HOME" -name '.profile'
raportează un timp mai lung decâttime find "$HOME" | grep -F '.profile'
. (17s vs. 12s). - @JenniferAnderson Am fugit amândoi în mod repetat. Cele 17 și 12 secunde sunt medii. Și da, variația
grep
se va potrivi oriunde în rezultatulfind
, în timp ce potrivirea cufind -name
s-ar potrivi doar exact (în acest caz). - Da,
find filename
ar fi rapid . Am presupus că este vorba despre o greșeală de eroare și că OP înseamnăfind -name filename
. Cufind filename
, numaifilename
ar fi examinat (și nimic altceva).
Răspunde
(presupun GNU find
aici)
Folosind doar
find filename
ar ar fi rapid, deoarece ar returna doar filename
, sau numele din filename
dacă este un director sau o eroare dacă numele respectiv nu a existat în directorul curent. Este „o operație foarte rapidă, similară cu ls filename
(dar recursiv dacă filename
este un director).
În în schimb,
find | grep filename
ar permite find
să genereze o listă cu toate numele din directorul curent și mai jos, care grep
ar fi apoi filtrat. Aceasta ar fi evident o operațiune mult mai lentă.
Presupun că ceea ce a fost de fapt intenționat a fost
find . -type f -name "filename"
Aceasta ar căuta filename
ca numele unui fișier obișnuit oriunde în directorul curent sau mai jos.
Acesta va fi la fel de rapid (sau comparativ rapid) ca find | grep filename
, dar grep
soluție s-ar potrivi cu filename
cu calea completă a fiecărui nume găsit, similar cu ceea ce ar face -path "*filename*"
cu find
.
Confuzia provine dintr-o neînțelegere a modului în care find
funcționează.
Utilitarul ia un număr de căi și returnează toate numele sub aceste căi.
Puteți apoi restricționează numele returnate folosind diferite teste care pot acționa asupra numelui fișierului, calea, marcajul de timp, dimensiunea fișierului, tipul fișierului etc.
Când spui
find a b c
solicitați find
să enumere fiecare nume disponibil sub cele trei căi a
, b
și c
. Dacă acestea se întâmplă să fie nume de fișiere obișnuite în directorul curent, atunci acestea vor fi returnate. Dacă se întâmplă ca oricare dintre ele să fie numele unui director, atunci acesta va fi returnat împreună cu toate numele suplimentare din acel director.
Când o fac
find . -type f -name "filename"
Aceasta generează o listă cu toate numele din directorul curent (.
) și mai jos. Apoi, restricționează numele la cele ale fișierelor obișnuite, adică nu directoare etc., cu -type f
. Apoi, există o restricție suplimentară la nume care se potrivește cu filename
folosind -name "filename"
. Șirul filename
poate fi un model de denumire a fișierelor, cum ar fi *.txt
(nu uitați să îl citați!).
Exemplu:
Următorul pare să „găsească” fișierul numit .profile
în directorul meu de acasă:
$ pwd /home/kk $ find .profile .profile
Dar, de fapt, returnează toate numele de pe calea .profile
(există un singur nume și este cel al acestui fișier).
Apoi, cd
urc un nivel și încerc din nou:
$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory
find
comanda nu poate găsi acum nicio cale numită .profile
.
Cu toate acestea, dacă îl fac să se uite la directorul curent și apoi restricționează numele returnate la numai .profile
, acesta va găsi și de acolo:
$ pwd /home $ find . -name ".profile" ./kk/.profile
Comentarii
Răspuns
Explicație non-tehnică: Îl cauți pe Jack într-o mulțime este mai rapid decât să cauți pe toată lumea dintr-o mulțime și să elimini toate din considerație, cu excepția lui Jack.
Comentarii
- Problema este că OP se așteaptă ca Jack să fii singura persoană din mulțime. Dacă este, au ‘ norocoși.
find jack
va afișajack
dacă este ‘ un fișier numitjack
, sau toate numele din director dacă este ‘ un director. ‘ este o neînțelegere a modului în care funcționeazăfind
.
Răspuns
Încă nu am înțeles problema, dar pot oferi mai multe informații.
La fel ca pentru Kusalananda apelul find | grep
este clar mai rapid pe sistemul meu, ceea ce nu are prea mult sens. La început am presupus un fel de problemă de tamponare; că scrierea pe consolă încetinește timpul până la următorul apel pentru citirea următorului nume de fișier. Scrierea pe o țeavă este foarte rapidă: aproximativ 40MiB / s chiar și pentru 32 de octeți (pe sistemul meu destul de lent; 300 MiB / s pentru o dimensiune de bloc de 1MiB). Astfel am presupus că find
poate citi mai repede din sistemul de fișiere atunci când scrieți pe o țeavă (sau fișier), astfel încât cele două operații care citesc căile de fișiere și să scrieți în consolă să poată rula în paralel ceea ce find
ca proces unic nu poate face singur.
Este find
„eroare
Compararea celor două apeluri
:> time find "$HOME"/ -name "*.txt" >/dev/null real 0m0.965s user 0m0.532s sys 0m0.423s
și
:> time find "$HOME"/ >/dev/null real 0m0.653s user 0m0.242s sys 0m0.405s
arată că find
face ceva incredibil de prost (oricare ar fi acesta). se dovedește a fi destul de incompetent la executarea -name "*.txt"
.
Ar putea depinde de raportul de intrare / ieșire
S-ar putea să credeți că find -name
câștigă dacă există foarte puțin de scris. Dar istul devine mai jenant pentru find
. Se pierde chiar dacă nu este nimic de scris împotriva fișierelor 200K (13 milioane de date de țeavă) pentru grep
:
time find /usr -name lwevhewoivhol
find
poate fi la fel de rapid ca grep
, deși
Se pare că prostia find
„cu name
nu se extinde la alte teste. Folosiți în schimb o regex și problema a dispărut:
:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s
Cred că acest lucru poate fi considerat un bug. Cineva dorește să depună un raport de eroare? Versiunea mea este find (GNU findutils) 4.6.0
Comentarii
- Cât de repetabile sunt calendarele dvs.? Dacă ați făcut mai întâi testul
-name
, este posibil să fi fost mai lent din cauza faptului că conținutul directorului nu a fost stocat în cache. (Când testez-name
și-regex
consider că durează aproximativ același timp, cel puțin odată ce efectul cache a fost luat în considerare. desigur, poate fi doar o versiune diferită afind
…) - @psmears Desigur, am făcut aceste teste de mai multe ori. Problema memorării în cache a fost menționată chiar și în comentariile la întrebarea dinaintea primului răspuns. Versiunea mea
find
este find (GNU findutils) 4.6.0 - De ce este surprinzător faptul că adăugarea
-name '*.txt'
încetineștefind
? Trebuie să facă o muncă suplimentară, testând fiecare nume de fișier. - @Barmar Pe de o parte, această lucrare suplimentară poate fi realizată extrem de rapid. Pe de altă parte, această lucrare suplimentară salvează alte lucrări.
find
trebuie să scrie mai puține date. Și scrierea pe o conductă este o operațiune mult mai lentă. - Scrierea pe un disc este foarte lentă, scrierea pe o conductă nu este atât de rea, ci doar copie într-un buffer de nucleu. Observați că la primul test, scrierea mai mult pe
/dev/null
a folosit cumva mai puțin timp de sistem.
Răspuns
Notificare : Voi presupune că vrei să spui find . -name filename
(în caz contrar, căutați lucruri diferite; find filename
privește de fapt o cale numită filename , care s-ar putea să nu conțină aproape niciun fișier, deci iese foarte repede).
Să presupunem că aveți un director care conține cinci mii de fișiere. Pe majoritatea sistemelor de fișiere, aceste fișiere sunt stocate într-o structură arbore , care permite localizarea rapidă a oricărui fișier dat.
Deci, când cereți find
să localizați un fișier al cărui nume necesită doar verificare, find
va cere pentru fișierul acel și numai acel fișier, către sistemul de fișiere de bază, care va citi foarte puține pagini din stocarea în masă. Deci, dacă sistemul de fișiere își merită sarea, această operațiune va rula mult mai repede decât parcurgând întregul arbore pentru a recupera toate intrările.
Când solicitați find
simplu, totuși exact ceea ce faci, parcurgi întregul copac, citind. Fiecare. Singur. Intrare. Cu directoare mari, aceasta ar putea fi o problemă (este exact motivul pentru care mai multe software-uri, care au nevoie să stocheze o mulțime de fișiere pe disc, vor crea „copaci de directoare” cu două sau trei componente adânci: în acest fel, fiecare frunză trebuie să conțină doar mai puține fișiere) .
Răspuns
Să presupunem că fișierul / john / paul / george / ringo / beatles există și fișierul pe care îl căutați se numește „pietre”
find / stones
find va compara „beatle” cu „pietre” și îl va lăsa atunci când „s” și „b” nu se potrivesc .
find / | grep stones
În acest caz, find va trece „/ john / paul / george / ringo / beatles” la grep și grep wil Trebuie să-mi croiesc drum prin întreaga cale înainte de a stabili dacă se potrivește.
Grep face, prin urmare, mult mai multă muncă, motiv pentru care durează mai mult
Comentarii
- Ați încercat asta?
- Costul comparațiilor șirului (extrem de simplu și ieftin) este complet micșorat de costul IO (sau doar syscall dacă este stocat în cache) din căutările de directoare.
- grep nu este ‘ o comparație de șiruri, comparația sa de expresie regulată, ceea ce înseamnă că trebuie să lucreze prin întregul șir până când găsește un meci sau ajunge la final. Căutările din director sunt aceleași indiferent de ce.
- @Paranoid Hm, despre ce versiune de găsi vorbești? Se pare că ‘ nu este altceva ca găsi Am ‘ obișnuit în debian.
find filename
ar returna numaifilename
dacăfilename
nu ar fi de tipul director (sau a fost de tip director, dar nu a avut nicio intrare în sine)