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 enntime 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 ifind
resultatet, mens samsvar medfind -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 betyddefind -name filename
. Medfind filename
vil barefilename
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).
Så 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
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 oppgijack
hvis det ‘ en fil som heterjack
, eller alle navnene i katalogen hvis den ‘ en katalog. Det ‘ er en misforståelse av hvordanfind
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 avfind
…) - @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'
bremserfind
? 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.
find filename
ville bare returnerefilename
hvisfilename
ikke var av typen katalog (eller var av typen katalog, men hadde ikke noen oppføring i seg selv)