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
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 find
– grep
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
-lippugrep
käytettäessäfind
. Voit nähdä, että se etsii yhä uudelleen samoja tiedostoja vertaamalla tapahtuneenopen
-määrää. - @qwertzguy, ei,
-r
pitäisi olla vaaraton, koska-type f
ei takaa, että mikään argumenteista ei ole hakemistoja. Useatopen()
s ovat todennäköisemmin muita tiedostoja, jotkagrep
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 luetellaangrep
, 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.
-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ö.-r
-vaihtoehtoa kohdassagrep
toiselle