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ât time 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 rezultatul find, în timp ce potrivirea cu find -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. Cu find filename, numai filename 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

  • find filename ar returna numai filename dacă filename nu ar fi de tipul director (sau a fost de tip director, dar nu a avut nicio intrare în sine)

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șa jack dacă este ‘ un fișier numit jack, 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ă a find …)
  • @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ște find? 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.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *