Jeg prøvde begge kommandoene og kommandoen find | grep "filename" er mange mange ganger tregere enn den enkle find "filename" -kommando.

Hva ville være en riktig forklaring på denne oppførselen?

Kommentarer

  • Du lister opp hver fil med find og deretter overfører dataene til grep for å behandle. Med finn brukt på den ‘ sin egen, mangler du trinnet for å sende alle listede filer til grep for å analysere utdataene. Dette blir derfor raskere.
  • Saktere i hvilken forstand? Tar kommandoene en annen tid å fullføre?
  • Jeg kan ‘ t gjengi dette lokalt. Hvis noe, rapporterer time find "$HOME" -name '.profile' lenger tid enn time find "$HOME" | grep -F '.profile'. (17s vs. 12s).
  • @JenniferAnderson Jeg løp begge gjentatte ganger. 17 og 12 sekunder er gjennomsnitt. Og ja, grep variasjonen vil matche hvor som helst i find resultatet, mens samsvar med find -name ville bare stemme overens nøyaktig (i dette tilfellet).
  • Ja, find filename ville være rask . Jeg antok ganske at dette var en skrivefeil, og at OP betydde find -name filename. Med find filename vil bare filename bli undersøkt (og ingenting annet).

Svar

(Jeg antar at GNU find her)

Bruker bare

find filename 

ville være raskt, fordi det bare ville returnere filename, eller navnene i filename hvis det er en katalog, eller en feil hvis navnet ikke eksisterte i den aktuelle katalogen. Det er en veldig rask operasjon, lik ls filename (men rekursiv hvis filename er en katalog).

I kontrast,

find | grep filename 

ville tillate find å generere en liste med alle navn fra den nåværende katalogen og under, som grep deretter vil filtrere. Dette ville åpenbart være en mye langsommere operasjon.

Jeg antar at det som var faktisk ment var

find . -type f -name "filename" 

Dette ville se etter filename som navnet på en vanlig fil hvor som helst i gjeldende katalog eller under.

Dette vil være like raskt (eller sammenlignbart raskt) som find | grep filename, men grep løsning ville matche filename mot hele banen til hvert funnet navn, på samme måte som -path "*filename*" ville gjort med find.


Forvirringen kommer av en misforståelse av hvordan find fungerer.

Verktøyet tar et antall baner og returnerer alle navn under disse banene.

Du kan da begrense de returnerte navnene ved hjelp av forskjellige tester som kan virke på filnavnet, banen, tidsstempelet, filstørrelsen, filtypen osv.

Når du sier

find a b c 

du ber find om å vise hvert tilgjengelig navn under de tre banene a, b og c. Hvis dette tilfeldigvis er navn på vanlige filer i den gjeldende katalogen, vil disse bli returnert. Hvis noen av dem tilfeldigvis er navnet på en katalog, vil den returneres sammen med alle ytterligere navn i den katalogen.

Når jeg gjør det

find . -type f -name "filename" 

Dette genererer en liste over alle navnene i den gjeldende katalogen (.) og under. Deretter begrenser det navnene til de vanlige filene, dvs. ikke kataloger osv., Med -type f. Deretter er det en ytterligere begrensning på navn som samsvarer med filename ved hjelp av -name "filename". Strengen filename kan være et filnavnmotiv, for eksempel *.txt (bare husk å sitere det!).

Eksempel:

Følgende ser ut til å «finne» filen som heter .profile i hjemmekatalogen min:

$ pwd /home/kk $ find .profile .profile 

Men faktisk returnerer det bare alle navn på banen .profile (det er bare ett navn, og det er denne filen).

cd opp et nivå og prøv igjen:

$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory 

find -kommandoen kan nå ikke finne noen bane som heter .profile.

Men hvis jeg får den til å se på den nåværende katalogen, og deretter begrenser de returnerte navnene til bare .profile , finner den det derfra også:

$ pwd /home $ find . -name ".profile" ./kk/.profile 

Kommentarer

  • find filename ville bare returnere filename hvis filename ikke var av typen katalog (eller var av typen katalog, men hadde ikke noen oppføring i seg selv)

Svar

Ikke-teknisk forklaring: Ser etter Jack i en mengde er raskere enn å lete etter alle i en mengde og eliminere alle fra hensyn utenom Jack.

Kommentarer

  • Problemet er at OP forventer at Jack skal være den eneste personen i mengden. Hvis det er, er de ‘ heldige. find jack vil oppgi jack hvis det ‘ en fil som heter jack, eller alle navnene i katalogen hvis den ‘ en katalog. Det ‘ er en misforståelse av hvordan find fungerer.

Svar

Jeg har ikke forstått problemet ennå, men kan gi litt mer innsikt.

Som for Kusalananda, ring find | grep er klart raskere på systemet mitt som ikke gir mye mening. Først antok jeg et slags buffringsproblem; at skriving til konsollen senker tiden til neste syscall for å lese neste filnavn. Å skrive til et rør er veldig raskt: omtrent 40MiB / s selv for 32-byte-skrivinger (på mitt ganske sakte system; 300 MiB / s for en blokkstørrelse på 1MiB). Dermed antok jeg at find kan lese fra filsystemet raskere når du skriver til et rør (eller en fil) slik at de to operasjonene som leser filbaner og skriver til konsollen kan kjøre parallelt ( som find som en enkelt trådprosess ikke kan gjøre alene.

Det «s find «s feil

Sammenligning av de to samtalene

:> time find "$HOME"/ -name "*.txt" >/dev/null real 0m0.965s user 0m0.532s sys 0m0.423s 

og

:> time find "$HOME"/ >/dev/null real 0m0.653s user 0m0.242s sys 0m0.405s 

viser at find gjør noe utrolig dumt (hva det måtte være). Det bare viser seg å være ganske inhabil ved å utføre -name "*.txt".

Kan avhenge av inngangs- / utgangsforholdet

Du tror kanskje at find -name vinner hvis det er veldig lite å skrive. Men jeg blir bare mer pinlig for find. Det taper selv om det ikke er noe å skrive i det hele tatt mot 200K filer (13M rørdata) for grep:

time find /usr -name lwevhewoivhol 

find kan være så raskt som grep, skjønt

Det viser seg at find «s dumhet med name ikke strekker seg til andre tester. Bruk en regex i stedet, og problemet er borte:

:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s 

Jeg antar at dette kan betraktes som en feil. Noen som er villige til å sende inn en feilrapport? Min versjon er find (GNU findutils) 4.6.0

Kommentarer

  • Hvor repeterbare er timingene dine? Hvis du først gjorde -name, kan det ha gått tregere på grunn av at kataloginnholdet ikke ble hurtigbufret. (Når vi tester -name og -regex synes jeg de tar omtrent samme tid, i det minste en gang cacheeffekten er tatt i betraktning. selvfølgelig kan det bare være en annen versjon av find …)
  • @psmears Selvfølgelig har jeg gjort disse testene flere ganger. Cache-problemet har blitt nevnt til og med i kommentarene til spørsmålet før det første svaret. Min find versjon er find (GNU findutils) 4.6.0
  • Hvorfor er det overraskende at det å legge til -name '*.txt' bremser find? Det må gjøre ekstra arbeid, teste hvert filnavn.
  • @Barmar Den ene siden dette ekstra arbeidet kan gjøres ekstremt raskt. På den annen side sparer dette ekstraarbeidet annet arbeid. find må skrive mindre data. Og å skrive til et rør er en mye langsommere operasjon.
  • Å skrive til en disk er veldig tregt, å skrive til et rør er ikke så ille, det kopieres bare til en kjernebuffer. Legg merke til at når du skrev mer til /dev/null, brukte du mindre systemtid på en eller annen måte.

Svar

Merk : Jeg antar at du mener find . -name filename (ellers leter du etter forskjellige ting; find filename ser faktisk på en bane som heter filnavn , som inneholder nesten ingen filer, og avsluttes derfor veldig raskt).


Anta at du har en katalog som inneholder fem tusen filer. På de fleste filsystemer er disse filene faktisk lagret i en tree struktur , som gjør det mulig å raskt finne en fil.

Så når du ber find om å finne en fil hvis navn bare krever kontroll, vil find spør for den filen, og bare den filen, til det underliggende filsystemet, som vil lese svært få sider fra masselagringen. Så hvis filsystemet er salt verdt, vil denne operasjonen kjøre mye raskere enn som krysser hele treet for å hente alle oppføringene.

Når du ber om vanlig find men det er nøyaktig hva du gjør, krysser du hele treet og leser. Hver. Enkel. Oppføring. Med store kataloger, dette kan være et problem (det er nøyaktig grunnen til at flere programvare, som trenger å lagre mange filer på disken, vil lage «katalogtrær» to eller tre komponenter dypt: på denne måten trenger hvert eneste blad bare å holde færre filer) .

Svar

La oss anta at filen / john / paul / george / ringo / beatles eksisterer og filen du søker etter kalles «steiner»

find / stones 

finne vil sammenligne «beatles» med «steiner» og slippe den når «s» og «b» ikke samsvarer .

find / | grep stones 

I dette tilfellet vil vil passere «/ john / paul / george / ringo / beatles» til grep og grep wil Jeg må jobbe meg gjennom hele banen før jeg avgjør om det er en kamp.

grep gjør derfor mye mer arbeid, det er derfor det tar lengre tid

Kommentarer

  • Har du prøvd det?
  • Kostnaden for streng sammenligningene (ekstremt enkel og billig) er helt dverg av IO (eller bare syscall hvis cached) kostnad av katalogoppslagene.
  • grep isn ‘ ta strengesammenligning, sammenligningen av regulært uttrykk, som betyr at den må jobbe seg gjennom hele strengen til den enten finner en kamp eller når slutten. Katalogoppslagene er de samme uansett.
  • @Paranoid Hm, hvilken versjon av finne snakker du om? Det ‘ er tilsynelatende ikke noe som funnet Jeg ‘ pleide å være i debian.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *