Care este mai eficient pentru a găsi care fișiere dintr-un întreg sistem de fișiere conțin un șir: grep recursiv sau găsi cu grep într-o instrucțiune exec? Presupun că găsirea ar fi mai eficientă deoarece puteți face cel puțin o filtrare dacă cunoașteți extensia de fișier sau o regex care se potrivește cu numele fișierului, dar când știți doar -type f ceea ce este mai bine ? GNU grep 2.6.3; găsi (GNU findutils) 4.4.2

Exemplu:

grep -r -i "the brown dog" /

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

Comentarii

  • Eficiența matematicii / informaticii / algoritmului în ‘ t aviz pe bază.
  • Bifați-l. Deși nu este recursiv, ar oferi o înțelegere asupra a ceea ce este mai bine. unix.stackexchange.com/questions/47983/…
  • @AvinashRaj el ‘ nu solicită opinie. El ‘ ‘ întreabă care este mai eficient și / sau mai rapid , nu care este ” mai bun „. Aceasta este o întrebare perfect răspunzătoare, care are un singur răspuns specific, care depinde de modul în care aceste două programe își fac treaba și de ce anume le dați să caute.
  • Rețineți că va face mai puține furculițe, deci ar trebui să fie mai rapid decât -exec {} \;. Poate fi necesar să adăugați -H (sau -h) la opțiunile grep pentru a obține exact ieșire echivalentă.
  • Probabil că nu ‘ nu doriți opțiunea -r pe grep pentru al doilea

Răspuns

Nu sunt sigur:

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

este ceea ce vrei să spui. Asta ar însemna grep recursiv în toate fișierele și direcțiile care nu sunt ascunse în / (dar uită-te totuși în fișierele și direcțiile ascunse din interiorul acestora).

Presupunând că ai vrut să spui:

grep -r -i "the brown dog" / 

Câteva lucruri de remarcat:

  • Nu toate implementările grep acceptă -r. Și dintre cele care o fac, comportamentele diferă: unii urmează link-uri simbolice către directoare atunci când traversează arborele directorului (ceea ce înseamnă că ați putea căuta ori verale în același fișier sau chiar rulate în bucle infinite), unele nu vor. Unii vor privi în fișierele dispozitivului (și va dura destul de mult timp în /dev/zero de exemplu) sau țevi sau fișiere binare …, altele nu.
  • Este „eficient deoarece grep începe să caute în fișiere imediat ce le descoperă. Dar, în timp ce privește un fișier, nu mai caută mai multe fișiere în care să caute (care este probabil la fel de bine în majoritatea cazurilor)

Tău:

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

(eliminat -r ceea ce nu avea sens aici) este teribil de ineficient, deoarece rulați un grep per fișier. ; trebuie utilizat numai pentru comenzile care acceptă un singur argument. Mai mult, aici, deoarece grep arată doar într-un singur fișier, nu va imprima numele fișierului, așa că nu veți ști unde sunt potrivirile.

Dumneavoastră ” nu vă uitați în fișiere, țevi, link-uri simbolice ale dispozitivului … nu urmăriți link-uri simbolice, dar încă căutați în interior lucruri precum /proc/mem.

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

ar fi mult mai bun deoarece s-ar rula cât mai puține comenzi grep. Ați primi numele fișierului, cu excepția cazului în care ultima rulare are un singur fișier. Pentru aceasta este mai bine să utilizați:

find / -type f -exec grep -i "the brown dog" /dev/null {} + 

sau cu GNU grep:

find / -type f -exec grep -Hi "the brown dog" {} + 

Rețineți că grep nu va fi pornit până la find a găsit suficiente fișiere pentru a le mesteca, deci va exista o întârziere inițială. Și find nu va continua să caute mai multe fișiere până când grep anterior nu a revenit. Alocarea și transmiterea listei mari de fișiere are un impact (probabil neglijabil), deci, în general, va fi probabil mai puțin eficient decât un grep -r care nu urmărește link-ul simbolic sau arată în interiorul dispozitivelor.

Cu instrumentele GNU:

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

Ca mai sus, cât mai puține grep instanțele cât mai posibile vor fi rulate, dar find va continua să caute mai multe fișiere în timp ce prima invocare grep caută în interiorul primului lot. Totuși, acest lucru poate fi sau nu un avantaj.De exemplu, cu datele stocate pe unitățile de disc rotative, find și grep accesând datele stocate în diferite locații de pe disc vor încetini discul randament prin determinarea mișcării constante a capului discului. Într-o configurație RAID (unde find și grep pot accesa diferite discuri) sau pe SSD-uri, aceasta ar putea face o diferență pozitivă.

Într-o configurare RAID, executarea mai multor invocații concurente grep ar putea îmbunătăți lucrurile. Încă cu instrumentele GNU pe stocarea RAID1 cu 3 discuri,

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

ar putea crește semnificativ performanța. Rețineți totuși că a doua grep va fi pornită numai după ce au fost găsite suficiente fișiere pentru a completa prima comandă grep. Puteți adăuga o opțiune -n la xargs pentru ca acest lucru să se întâmple mai repede (și să treceți mai puține fișiere pe grep invocare).

Rețineți, de asemenea, că dacă „redirecționați xargs ieșire către orice altceva decât un dispozitiv terminal, atunci greps s vor începe bufferizarea ieșirii, ceea ce înseamnă că ieșirea celor grep va fi probabil intercalată incorect. Trebuie să utilizați stdbuf -oL (acolo unde este disponibil ca pe GNU sau FreeBSD) pe ele pentru a rezolva acest lucru (este posibil să aveți în continuare probleme cu liniile foarte lungi (de obicei> 4KiB)) sau să vă scrieți ieșirea într-un fișier separat și să le concatenați pe toate la final.

Aici, șirul pe care îl căutați este fix (nu un regexp), astfel încât utilizarea opțiunii -F ar putea face o diferență (puțin probabil ca grep implementările știu cum să le optimizeze deja).

Un alt lucru Ld face o mare diferență este fixarea localizării la C dacă „vă aflați într-o localizare multi-octet:

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

Pentru a evita să priviți în interior /proc, /sys …, utilizați -xdev și specificați sistemele de fișiere în care doriți să căutați:

LC_ALL=C find / /home -xdev -type f -exec grep -i "the brown dog" /dev/null {} + 

Sau tăiați căile pe care doriți să le excludeți în mod explicit:

LC_ALL=C find / \( -path /dev -o -path /proc -o -path /sys \) -prune -o \ -type f -exec grep -i "the brown dog" /dev/null {} + 

Comentarii

  • Nu ‘ presupun că cineva mă poate îndrepta către o resursă – sau poate explica – ce înseamnă {} și +. ‘ nu pot vedea nimic în paginile de manual pentru exec, grep sau găsi în caseta Solaris pe care ‘ m îl folosesc. Este doar shell-ul concatenând numele fișierelor și trecându-le la grep?
  • @Poldie, ‘ este clar explicat la descrierea -exec predicat în pagina manuală Solaris
  • Ah, da. Nu ‘ nu scăpam de {char în timp ce căutam în pagina manuală. Link-ul dvs. este mai bun; Mi se pare grozav de citit paginile de manual.
  • RAID1 cu 3 discuri? Ce ciudat …
  • @tink, da RAID1 este pe 2 sau mai multe discuri. Cu 3 discuri comparativ cu 2 discuri, creșteți redundanța și citiți performanța, în timp ce performanța la scriere este aproximativ aceeași. Cu 3 discuri spre deosebire de 2, asta înseamnă că puteți corecta și erorile, deoarece atunci când un bit rotește pe una dintre copii, ‘ rețineți ce este corect verificând toate 3 exemplare în timp ce aveți 2 discuri, ‘ nu puteți spune cu adevărat.

Răspundeți

Dacă * din apelul grep nu este important pentru dvs., atunci primul ar trebui să fie mai eficient ca unul singur instanța grep este pornită, iar furculițele nu sunt gratuite. În majoritatea cazurilor va fi mai rapid chiar și cu *, dar în cazurile marginale sortarea ar putea inversa acest lucru.

S-ar putea să existe și alte findgrep care funcționează mai bine mai ales cu multe mici fișierele. Citirea unei cantități mari de intrări de fișiere și inoduri simultan poate oferi o îmbunătățire a performanței pe suportul rotativ.

Dar să aruncăm o privire asupra statisticilor de acces:

găsi

> 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 

grep only

> 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 

Comentarii

  • La scara de căutare a unui întreg sistem de fișiere, furculițele sunt neglijabile. I / O este ceea ce doriți să reduceți.
  • Deși este o eroare din OP, comparația este incorectă, ar trebui să eliminați semnalizatorul -r al grep când utilizați find. Puteți vedea că a căutat în repetate rânduri aceleași fișiere comparând numărul de open care s-a întâmplat.
  • @qwertzguy, nu, -r ar trebui să fie inofensiv, deoarece -type f garantează că niciunul dintre argumente nu este directoare. Mai multe open() s sunt mai probabil la celelalte fișiere deschise de grep la fiecare invocație (biblioteci, date de localizare …) ( mulțumesc pentru modificarea răspunsului meu btw)

Răspuns

Dacă sunteți pe un SSD și căutați timp este neglijabil, puteți utiliza paralela GNU:

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

Aceasta va executa până la 8 procese grep în același timp, pe baza a ceea ce find găsit.

Acest lucru va arunca o unitate de hard disk, dar un SSD ar trebui să facă față destul de bine.

Răspuns

Încă un lucru de luat în considerare în acest sens este următorul.

Vor avea vreunul dintre directoarele prin care grep va trebui să treacă recursiv mai mult fișiere decât setarea nofile a sistemului dvs.? (de exemplu, numărul de mânere de fișiere deschise, implicit este 1024 pentru majoritatea distribuțiilor Linux)

Dacă da, atunci găsi este cu siguranță calea de urmat, deoarece anumite versiuni ale grep va bombarda cu o Listă de argumente prea lungă atunci când accesează un director cu mai multe fișiere decât fișierul maxim deschis gestionează setarea.

Doar 2 ¢.

Comentarii

  • De ce ar grep bomb out? Cel puțin cu GNU grep dacă dați o cale cu / și utilizați -R ‘ Voi pur și simplu itera prin directoare. shell nu ‘ nu va extinde nimic decât dacă dați shell-globs. Deci, în exemplul dat (/*) contează doar conținutul /, nu din subfolderele care vor fi enumerate simplu de grep, nu a fost transmis ca argument din shell.
  • Ei bine, având în vedere că OP a întrebat despre căutarea recursivă (de ex. ” grep -r -i ‘ câinele brun ‘ / * „), am văzut GNU ‘ s grep (cel puțin versiunea 2.9) bombă cu: ” -bash: / bin / grep: Listă de argumente prea lungă ” folosind căutarea exactă pe care OP a folosit-o pe un director care avea peste 140.000 de subdirectoare în el.

Lasă un răspuns

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