Kumpi on tehokkaampi löytääksesi, mitkä koko tiedostojärjestelmän tiedostot sisältävät merkkijonon: rekursiivinen grep tai etsittävä grepillä exec-käskyssä? Oletan, että haku olisi tehokkaampaa, koska voit ainakin tehdä jonkin verran suodatusta, jos tiedät tiedostopääte tai regex, joka vastaa tiedostonimeä, mutta kun tiedät vain -type f, mikä on parempi ? GNU grep 2.6.3; etsi (GNU findutils) 4.4.2

Esimerkki:

grep -r -i "the brown dog" /

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

Kommentit

  • Matematiikan / tietojenkäsittelytieteen / algoritmin tehokkuus ins ’ t lausunto perustuu.
  • Tarkista tämä. Vaikka se ei ole rekursiivinen, se antaisi ymmärryksen siitä, mikä on parempi. unix.stackexchange.com/questions/47983/…
  • @AvinashRaj he ’ eivät pyydä mielipidettä. Hän ’ ’ kysyy, mikä on tehokkaampi ja / tai nopeampi , mikä ei ole ” parempi ”. Tämä on täysin vastattava kysymys, jolla on yksi erityinen vastaus, joka riippuu siitä, miten nämä kaksi ohjelmaa tekevät työnsä ja mitä annat heille etsiä.
  • Huomaa, että -exec {} + -lomake tekee vähemmän haarukoita, joten sen pitäisi olla nopeampi kuin -exec {} \;. Saatat joutua lisäämään -H (tai -h) grep -vaihtoehtoihin saadaksesi tarkalleen vastaava lähtö.
  • Et todennäköisesti halunnut ’ halunnut -r -vaihtoehtoa kohdassa grep toiselle

Vastaa

En ole varma:

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

tarkoitit oikeastaan. Se tarkoittaisi grep rekursiivisesti kaikki piilotetut tiedostot ja hakemistot / (mutta katsokaa silti piilotettujen tiedostojen sisäpuolella ja niiden sisällä).

Oletetaan, että tarkoititte:

grep -r -i "the brown dog" / 

Huomioitavaa:

  • Kaikki grep -toteutukset eivät tue -r. Ja niiden joukossa käyttäytyminen eroaa toisistaan: jotkut seuraavat hakemistojen linkkejä hakemistoon siirtyessään (mikä tarkoittaa, että saatat päätyä etsimään samassa tiedostossa tai jopa ajaa äärettömissä silmukoissa), jotkut eivät. Jotkut katsovat laitetiedostoista (ja esimerkiksi /dev/zero: ssä kestää jonkin aikaa) tai putkista tai binaaritiedostoista …, toiset eivät.
  • Se on tehokasta, kun grep alkaa etsiä tiedostoja sisälle heti, kun ne löytää ne. Mutta vaikka se näyttää tiedostossa, se ei enää etsi lisää tiedostoja, joista hakea (mikä on todennäköisesti yhtä hyvä useimmissa tapauksissa)

Sinun:

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

(poisti -r jolla ei ollut järkeä tässä) on hirveän tehoton, koska suoritat yhtä grep tiedostoa kohden. ; tulisi käyttää vain komennoille, jotka hyväksyvät vain yhden argumentin. Lisäksi tässä, koska grep näyttää vain yhdessä tiedostossa, se ei tulosta tiedostonimeä, joten et tiedä, missä osumat ovat.

Sinä ” et katso laitetiedostoista, putkista, symlinkeistä …, et seuraa symlinkkejä, mutta etsit silti mahdollisesti sellaisia asioita kuin /proc/mem.

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

olisi paljon parempi, koska suoritettaisiin mahdollisimman vähän grep -komentoja. Saat tiedostonimen, ellei viimeisellä ajolla on vain yksi tiedosto. Sitä varten on parempi käyttää sitä:

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

tai GNU: n kanssa grep:

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

Huomaa, että grep aloitetaan vasta find on löytänyt tarpeeksi tiedostoja pureskeltavaksi, joten alkuviiveellä on jonkin verran aikaa. Ja find ei jatka uusien tiedostojen hakemista, ennen kuin edellinen grep on palannut. Suuren tiedostoluettelon jakamisella ja välittämisellä on jonkin verran (luultavasti vähäpätöistä) vaikutusta, joten kaiken kaikkiaan se todennäköisesti on vähemmän tehokasta kuin grep -r, joka ei seuraa symlinkkiä tai etsiä laitteiden sisällä.

GNU-työkaluilla:

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

Kuten yllä, niin vähän grep mahdolliset esiintymät suoritetaan, mutta find jatkaa uusien tiedostojen etsimistä, kun taas ensimmäinen grep kutsu etsii ensimmäisen erän sisälle. Se voi kuitenkin olla etu.Esimerkiksi pyöriville kiintolevyille tallennetuilla tiedoilla find ja grep, jotka käyttävät levyn eri paikkoihin tallennettuja tietoja, levy hidastuu. läpäisykykyä aiheuttamalla levyn pään jatkuvan liikkumisen. RAID-asennuksessa (jossa find ja grep voi käyttää eri levyjä) tai SSD-levyillä, tämä saattaa vaikuttaa positiivisesti.

RAID-asetuksissa useiden samanaikaisten grep kutsujen suorittaminen voi myös parantaa asioita. Edelleen GNU-työkalujen kanssa RAID1-tallennustilassa, jossa on kolme levyä,

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

saattaa parantaa suorituskykyä merkittävästi. Huomaa kuitenkin, että toinen grep käynnistetään vasta, kun on löydetty tarpeeksi tiedostoja täyttämään ensimmäinen grep -komento. Voit lisätä -n -asetuksen kohtaan xargs, jotta se tapahtuisi nopeammin (ja välittäisi vähemmän tiedostoja grep invocation).

Huomaa myös, että jos ”uudelleenohjaat xargs -lähdön mihinkään muuhun kuin päätelaitteeseen, niin greps s alkavat puskuroida lähtöään, mikä tarkoittaa, että näiden grep -lähteiden lomitus on todennäköisesti väärin lomitettu. Sinun on käytettävä stdbuf -oL (jos saatavilla, kuten GNU: ssa tai FreeBSD: ssä) heille kiertääksesi ongelman (sinulla voi silti olla ongelmia hyvin pitkien rivien kanssa (tyypillisesti> 4KiB)) tai anna jokaisen kirjoittaa tuotoksensa erilliseen tiedostoon ja liittää ne kaikki yhteen lopulta.

Tässä etsimäsi merkkijono on korjattu (ei regexp), joten -F -vaihtoehdon käyttäminen saattaa vaikuttaa (todennäköisesti epätodennäköisenä) grep toteutukset osaavat optimoida sen jo).

Toinen asia, joka yhdistetään Ld: llä on suuri ero, että paikallinen kieli korjataan C: ksi, jos olet monitavuisessa kielialueessa:

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

Välttää katsomasta /proc, /sys …, käytä -xdev ja määritä tiedostojärjestelmät, joista haluat etsiä:

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

Tai leikkaa polut, jotka haluat nimenomaisesti sulkea pois:

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

Kommentit

  • En ’ usko, että joku voi osoittaa minulle resurssia – tai selittää – mitä {} ja + tarkoittavat. Siellä ’ ei ole mitään, mitä en näe man-sivuilla exec-, grep- tai Solaris-ruudusta i ’ m. Onko vain kuori liitetty tiedostonimiin ja välittämällä ne grepiin?
  • @Poldie, että ’ selitetään selvästi predikaatti Solariksen man-sivulla
  • Ah, kyllä. En päässyt ’ pakenemaan {hiiltäni etsiessäni man-sivulta. Linkkisi on parempi; Mielestäni man-sivuja on kauheaa lukea.
  • RAID1 w / 3-levyillä? Kuinka outoa …
  • @tink, kyllä RAID1 on vähintään kahdella levyllä. Kolme levyä verrattuna kahteen levylle lisäävät redundanssia ja lukutehoa, kun taas kirjoitusteho on suunnilleen sama. Kun käytössä on 3 levyä, toisin kuin 2, se tarkoittaa, että voit myös korjata virheet, sillä kun bitti kääntää toista kopiota, ’ pystyt kertomaan, mikä on oikea tarkistamalla kaikki Kolme kopiota, kun taas 2 levyä, voit ’ t todellakin kertoa.

Vastaa

Jos * grep -puhelussa ei ole sinulle tärkeää, ensimmäisen tulisi olla tehokkaampi, koska vain yksi grep -esimerkki käynnistetään, ja haarukat eivät ole vapaita. Useimmissa tapauksissa se on nopeampi, vaikka *, mutta reunatapauksissa lajittelu voi kääntää sen.

Saattaa olla muita findgrep rakenteita, jotka toimivat paremmin erityisesti monien pienten kanssa Tiedostojen lukeminen suurella määrällä tiedostomerkintöjä ja inodeja voi parantaa suorituskykyä kiertävässä mediassa.

Katsotaanpa kuitenkin syscall-tilastoja:

etsi

> 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 

vain grep

> 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 

kommentit

  • Haarukat ovat merkityksettömiä koko tiedostojärjestelmän haun mittakaavassa. I / O on se, mitä haluat vähentää.
  • Vaikka se onkin OP: n virhe, vertailu on virheellinen, poista -r -lippu grep käytettäessä find. Voit nähdä, että se etsii yhä uudelleen samoja tiedostoja vertaamalla tapahtuneen open -määrää.
  • @qwertzguy, ei, -r pitäisi olla vaaraton, koska -type f ei takaa, että mikään argumenteista ei ole hakemistoja. Useat open() s ovat todennäköisemmin muita tiedostoja, jotka grep avaa jokaisessa kutsussa (kirjastot, lokalisointitiedot …) ( kiitos vastauksestani muokkauksesta btw)

Vastaa

Jos olet SSD-levyllä ja haet aikaa on vähäpätöinen, voit käyttää GNU-rinnakkaista:

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

Tämä suorittaa jopa 8 grep-prosessia samanaikaisesti sen perusteella, mitä find löytyi.

Tämä tuhoaa kiintolevyn, mutta SSD: n pitäisi selviytyä siitä melko hyvin.

Vastaa

Vielä yksi huomioitava asia tässä on seuraava.

Sisältääkö jokin hakemistoista, joita grep on rekursiivisesti käytävä läpi, enemmän tiedostoja kuin järjestelmän nofile -asetusta? (esim. avoimien tiedostokahvojen lukumäärä, oletusarvo on 1024 useimmissa Linux-distroissa)

Jos näin on, etsi on ehdottomasti oikea tapa edetä, koska tietyt grep pommitetaan argumenttiluettelolla liian pitkä -virhe, kun se osuu hakemistoon, jossa on enemmän tiedostoja kuin suurin avoin tiedosto käsittelee asetuksia.

Vain minun 2 ¢.

Kommentit

  • Miksi grep pommittaa? Ainakin GNU grep -toiminnon avulla, jos annat polun, jonka lopussa on / ja käytät -R it ’ Toistan vain hakemistot. Kuori ei ole ’ aio laajentaa mitään, ellet anna shell-maapalloja. Joten annetussa esimerkissä (/*) vain / -sisällöllä on merkitystä, ei alikansioissa, jotka yksinkertaisesti luetellaan grep, ei lähetetty argumenttina kuoresta.
  • Harkitessaan OP: ta kysyttiin rekursiivisesta hausta (esim. ” grep -r -i ’ ruskea koira ’ / * ”), olen nähnyt GNU ’ s grep (vähintään versio 2.9) pommi: ” -bash: / bin / grep: Argumenttiluettelo on liian pitkä ” käyttämällä tarkkaa hakua OP: lle, jota käytettiin hakemistossa, jossa oli yli 140 000 alihakemistoa.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *