Jeg prøvede begge kommandoer, og kommandoen find | grep "filename"
er mange mange gange langsommere end den enkle find "filename"
kommando.
Hvad ville være en korrekt forklaring på denne adfærd?
Kommentarer
- Dig viser hver fil med find og videregiver derefter dataene til grep for at behandle dem. Med find brugt på det ‘ s eget, mangler du trinnet med at videresende alle listede filer til grep for at analysere output. Dette vil derfor være hurtigere.
- Langsom i hvilken forstand? Det tager forskellige tid at udføre kommandoerne?
- Jeg kan ‘ t gengive dette lokalt. Hvis der er noget, rapporterer
time find "$HOME" -name '.profile'
længere tid endtime find "$HOME" | grep -F '.profile'
. (17ere mod 12ere). - @JenniferAnderson Jeg løb begge gentagne gange. 17 og 12 sekunder er gennemsnit. Og ja,
grep
variationen vil matche hvor som helst ifind
resultatet, mens matchning medfind -name
ville kun matche nøjagtigt (i dette tilfælde). - Ja,
find filename
ville være hurtig . Jeg antog lidt, at dette var en skrivefejl, og at OP betødfind -name filename
. Medfind filename
ville kunfilename
blive undersøgt (og intet andet).
Svar
(Jeg antager, at GNU find
her)
Brug bare
find filename
ville være hurtig, fordi det bare ville returnere filename
, eller navnene inde i filename
hvis det er en mappe, eller en fejl, hvis navnet ikke eksisterede i den aktuelle mappe. Det er en meget hurtig betjening svarende til ls filename
(men rekursiv, hvis filename
er et bibliotek).
I kontrast
find | grep filename
ville tillade find
at generere en liste med alle navne fra det aktuelle bibliotek og derunder, som grep
derefter ville filtrere. Dette ville naturligvis være en meget langsommere handling.
Jeg antager, at hvad der var faktisk beregnet var
find . -type f -name "filename"
Dette ville se efter filename
som navnet på en almindelig fil hvor som helst i det aktuelle bibliotek eller derunder.
Dette vil være lige så hurtigt (eller sammenligneligt hurtigt) som find | grep filename
, men grep
løsning ville matche filename
mod den fulde sti for hvert fundet navn, på samme måde som -path "*filename*"
ville gøre med find
.
Forvirringen kommer fra en misforståelse af, hvordan find
fungerer.
Hjælpeprogrammet tager et antal stier og returnerer alle navne under disse stier.
Du kan derefter begrænse de returnerede navne ved hjælp af forskellige tests, der kan virke på filnavnet, stien, tidsstemplet, filstørrelsen, filtypen osv.
Når du siger
find a b c
du beder find
om at liste hvert tilgængeligt navn under de tre stier a
, b
og c
. Hvis dette tilfældigvis er navne på almindelige filer i den aktuelle mappe, returneres disse. Hvis nogen af dem tilfældigvis er navnet på en mappe, returneres den sammen med alle yderligere navne i den mappe.
Når jeg gør
find . -type f -name "filename"
Dette genererer en liste med alle navne i den aktuelle mappe (.
) og derunder. Derefter begrænser det navnene til almindelige filer, dvs. ikke mapper osv., Med -type f
. Derefter er der en yderligere begrænsning af navne, der matcher filename
ved hjælp af -name "filename"
. Strengen filename
kan være et filnavnet globbing mønster, såsom *.txt
(husk bare at citere det!).
Eksempel:
Følgende synes at “finde” filen med navnet .profile
i min hjemmekatalog:
$ pwd /home/kk $ find .profile .profile
Men faktisk returnerer det bare alle navne på stien .profile
(der er kun ét navn, og det er denne fil).
Så cd
et niveau op og prøv igen:
$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory
find
-kommandoen kan nu ikke finde nogen sti, der hedder .profile
.
Men hvis jeg får det til at se på den aktuelle mappe og derefter begrænser de returnerede navne til kun .profile
, finder den det derfra også:
$ pwd /home $ find . -name ".profile" ./kk/.profile
Kommentarer
Svar
Ikke-teknisk forklaring: På udkig efter Jack i en skare er hurtigere end at lede efter alle i en skare og fjerne alle fra overvejelse undtagen Jack.
Kommentarer
- Problemet er, at OP forventer, at Jack skal være den eneste person i mængden. Hvis det er tilfældet, er de ‘ heldige.
find jack
viserjack
hvis det ‘ en fil med navnetjack
eller alle navne i biblioteket, hvis det ‘ er et bibliotek. Det ‘ er en misforståelse af, hvordanfind
fungerer.
Svar
Jeg har ikke forstået problemet endnu, men kan give nogle flere indsigter.
Ligesom for Kusalananda kaldes find | grep
er klart hurtigere på mit system, hvilket ikke giver meget mening. Først antog jeg en form for bufferingsproblem; at skrivning til konsollen bremser tiden til næste syscall til læsning af det næste filnavn. At skrive til et rør er meget hurtigt: ca. 40MiB / s selv til 32-byte-skrivning (på mit ret langsomme system; 300 MiB / s for en blokstørrelse på 1MiB). Jeg antog således, at find
kan læse fra filsystemet hurtigere, når man skriver til et rør (eller en fil), så de to operationer, der læser filstier og skriver til konsollen, kan køre parallelt ( som find
som en enkelt trådproces ikke kan gøre alene.
Det “s find
“s fejl
Sammenligning af de to opkald
:> 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
gør noget utroligt dumt (hvad det måtte være). viser sig at være ret inhabil ved udførelse af -name "*.txt"
.
Kan afhænge af input / output-forholdet
Du tror måske, at find -name
vinder, hvis der er meget lidt at skrive. Men jeg bliver bare mere pinligt for find
. Det taber, selvom der slet ikke er noget at skrive mod 200K filer (13M rørdata) for grep
:
time find /usr -name lwevhewoivhol
find
kan være så hurtig som grep
, selvom
Det viser sig, at find
“s dumhed med name
ikke udvides til andre tests. Brug en regex i stedet, og problemet er væk:
:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s
Jeg antager, at dette kan betragtes som en fejl. Er nogen villige til at indgive en fejlrapport? Min version er find (GNU findutils) 4.6.0
Kommentarer
- Hvor gentagelige er dine timinger? Hvis du først testede
-name
, kan det have været langsommere på grund af biblioteksindholdet, der ikke blev cache. (Når vi tester-name
og-regex
finder jeg, at de tager omtrent samme tid, i det mindste når cacheeffekten er taget i betragtning. selvfølgelig kan det bare være en anden version affind
…) - @psmears Selvfølgelig har jeg lavet disse tests flere gange. Cache-problemet er blevet nævnt selv i kommentarerne til spørgsmålet før det første svar. Min
find
version er find (GNU findutils) 4.6.0 - Hvorfor er det overraskende at tilføje
-name '*.txt'
find
? Det skal udføre ekstra arbejde ved at teste hvert filnavn. - @Barmar På den ene side kan dette ekstra arbejde udføres ekstremt hurtigt. På den anden side sparer dette ekstra arbejde andet arbejde.
find
skal skrive færre data. Og at skrive til et rør er en meget langsommere handling. - At skrive til en disk er meget langsom, at skrive til et rør er ikke så slemt, det kopieres bare til en kernebuffer. Bemærk, at du ved din første test ved at skrive mere til
/dev/null
på en eller anden måde brugte mindre systemtid.
Svar
Bemærk : Jeg antager, at du mener find . -name filename
(ellers leder du efter forskellige ting; find filename
ser faktisk på en sti kaldet filnavn , som indeholder muligvis næsten ingen filer og afsluttes derfor meget hurtigt).
Antag at du har en mappe med fem tusind filer. På de fleste filsystemer er disse filer faktisk gemt i en træ struktur , som gør det muligt hurtigt at finde en given fil.
Så når du beder find
om at finde en fil, hvis navn kun kræver kontrol, vil find
spørge til den fil, og kun den fil, til det underliggende filsystem, som vil læse meget få sider fra masselagring. Så hvis filsystemet er saltet værd, kører denne handling meget hurtigere end , der gennemgår hele træet for at hente alle poster.
Når du beder om almindelig find
men det er nøjagtigt hvad du laver, krydser du hele træet og læser. Hver. Enkel. Indgang. Med store mapper, dette kan være et problem (det er nøjagtigt grunden til, at flere software, der har brug for at gemme mange filer på disken, vil skabe “katalogtræer” to eller tre komponenter dybt: på denne måde behøver hvert enkelt blad kun at holde færre filer) .
Svar
Lad os antage, at filen / john / paul / george / ringo / beatles findes, og den fil du søger efter kaldes “sten”
find / stones
find vil sammenligne “beatles” med “sten” og droppe det, når “s” og “b” ikke matcher .
find / | grep stones
I dette tilfælde finder vil passere “/ john / paul / george / ringo / beatles” til grep og grep wil Jeg er nødt til at arbejde sig gennem hele stien, før jeg bestemmer, om det er et match.
grep gør derfor langt mere arbejde, hvorfor det tager længere tid
Kommentarer
- Har du prøvet det?
- Omkostningerne ved strengesammenligninger (ekstremt enkle og billige) er helt dværg af IO (eller bare syscall hvis cache) omkostninger af katalogopslag.
- grep isn ‘ ta-sammenligning af streng, dens sammenligning med regelmæssigt udtryk, hvilket betyder, at den skal arbejde sig gennem hele strengen, indtil den enten finder en kamp eller når slutningen. Katalogopslag er de samme uanset hvad.
- @Paranoid Hm, hvilken version af find taler du om? Det ‘ er tilsyneladende ikke noget som find I ‘ plejede at være i debian.
find filename
ville kun returnerefilename
hvisfilename
ikke var af typen katalog (eller var af typen katalog, men havde ikke nogen post i sig selv)