Jag försökte båda kommandona och kommandot find | grep "filename"
är många många gånger långsammare än det enkla find "filename"
-kommando.
Vad skulle vara en korrekt förklaring för detta beteende?
Kommentarer
- Du listar varje fil med hitta och skickar sedan data till grep för att bearbeta. När sökningen används på den ’ s saknar du steget att skicka alla listade filer till grep för att analysera utdata. Detta blir därför snabbare.
- Långsammare i vilken mening? Tar kommandona en annan tid att slutföra?
- Jag kan ’ t återge detta lokalt. Om något rapporterar
time find "$HOME" -name '.profile'
en längre tid äntime find "$HOME" | grep -F '.profile'
. (17s vs 12s). - @JenniferAnderson Jag sprang båda upprepade gånger. 17 och 12 sekunder är medelvärden. Och ja,
grep
-varianten matchar var som helst ifind
-resultatet, medan matchning medfind -name
skulle bara matcha exakt (i det här fallet). - Ja,
find filename
skulle vara snabb . Jag antog ganska att detta var ett stavfel och att OP menadefind -name filename
. Medfind filename
skulle endastfilename
undersökas (och inget annat).
Svara
(jag antar att GNU find
här)
Använd bara
find filename
skulle vara snabbt, eftersom det bara skulle returnera filename
, eller namnen i filename
om det är en katalog, eller ett fel om det namnet inte fanns i den aktuella katalogen. Det är en mycket snabb funktion, liknande ls filename
(men rekursiv om filename
är en katalog).
I kontrast
find | grep filename
skulle tillåta find
att skapa en lista med alla namn från den aktuella katalogen och nedan, som grep
sedan skulle filtrera. Detta skulle uppenbarligen vara en mycket långsammare operation.
Jag antar att det som var faktiskt avsedda var
find . -type f -name "filename"
Detta skulle leta efter filename
som namnet på en vanlig fil var som helst i den aktuella katalogen eller nedan.
Detta kommer att vara lika snabbt (eller jämförbart snabbt) som find | grep filename
, men grep
lösning skulle matcha filename
mot hela sökvägen för varje hittat namn, på samma sätt som -path "*filename*"
skulle göra med find
.
Förvirringen kommer från ett missförstånd om hur find
fungerar.
Verktyget tar ett antal banor och returnerar alla namn under dessa sökvägar.
Du kan då begränsa de returnerade namnen med hjälp av olika tester som kan verka på filnamnet, sökvägen, tidsstämpeln, filstorleken, filtypen etc.
När du säger
find a b c
du ber find
att lista alla tillgängliga namn under de tre sökvägarna a
, b
och c
. Om det här är namnen på vanliga filer i den aktuella katalogen kommer dessa att returneras. Om någon av dem råkar vara namnet på en katalog så returneras den tillsammans med alla ytterligare namn i den katalogen.
När jag gör det
find . -type f -name "filename"
Detta genererar en lista med alla namn i den aktuella katalogen (.
) och nedan. Sedan begränsar det namnen till de vanliga filerna, dvs. inte kataloger etc., med -type f
. Sedan finns det en ytterligare begränsning av namn som matchar filename
med -name "filename"
. Strängen filename
kan vara ett globnamn för filnamn, till exempel *.txt
(kom bara ihåg att citera det!).
Exempel:
Följande verkar ”hitta” filen som heter .profile
i min hemkatalog:
$ pwd /home/kk $ find .profile .profile
Men i själva verket returnerar det bara alla namn på sökvägen .profile
(det finns bara ett namn och det är den här filen).
Sedan
upp en nivå och försök igen:
$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory
find
-kommandot kan nu inte hitta någon sökväg som heter .profile
.
Men om jag får det att titta på den aktuella katalogen och sedan begränsar de returnerade namnen till endast .profile
hittar den det därifrån också:
$ pwd /home $ find . -name ".profile" ./kk/.profile
Kommentarer
Svar
Icke-teknisk förklaring: Letar efter Jack i en folkmassa är snabbare än att leta efter alla i en folkmassa och eliminera allt från övervägande utom Jack.
Kommentarer
- Problemet är att OP förväntar sig att Jack ska vara den enda personen i publiken. Om det är så har de ’ tur.
find jack
listarjack
om det ’ en fil som heterjack
, eller alla namn i katalogen om det ’ är en katalog. Det ’ är ett missförstånd om hurfind
fungerar.
Svar
Jag har inte förstått problemet ännu men kan ge lite mer insikter.
Som för Kusalananda ring find | grep
är tydligt snabbare på mitt system vilket inte ger mycket mening. Först antog jag något slags buffringsproblem; att skrivning till konsolen fördröjer tiden till nästa syscall för läsning av nästa filnamn. Att skriva till ett rör är väldigt snabbt: cirka 40MiB / s även för 32-bytes skrivningar (på mitt ganska långsamma system; 300 MiB / s för en blockstorlek på 1MiB). Således antog jag att find
kan läsa från filsystemet snabbare när man skriver till ett rör (eller fil) så att de två operationerna som läser filvägar och skriver till konsolen kan köras parallellt ( som find
som en enda trådprocess inte kan göra på egen hand.
Det ”s find
”s fel
Jämför de två samtalen
:> time find "$HOME"/ -name "*.txt" >/dev/null real 0m0.965s user 0m0.532s sys 0m0.423s
och
:> time find "$HOME"/ >/dev/null real 0m0.653s user 0m0.242s sys 0m0.405s
visar att find
gör något otroligt dumt (vad det än kan vara). visar sig vara ganska inkompetent vid körning av -name "*.txt"
.
Kan bero på input / output ratio
Du kanske tror att find -name
vinner om det är väldigt lite att skriva. Men jag blir bara mer pinsamt för find
. Det förlorar även om det inte finns något att skriva alls mot 200K-filer (13M rördata) för grep
:
time find /usr -name lwevhewoivhol
find
kan vara lika snabbt som grep
, men
Det visar sig att find
”s dumhet med name
inte omfattar andra tester. Använd en regex istället och problemet är borta:
:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s
Jag antar att detta kan betraktas som ett fel. Någon som är villig att skicka in en felrapport? Min version är find (GNU findutils) 4.6.0
Kommentarer
- Hur repeterbara är dina tidsinställningar? Om du gjorde testet
-name
kan det ha varit långsammare på grund av att kataloginnehållet inte cachades. (När vi testar-name
och-regex
tycker jag att de tar ungefär samma tid, åtminstone när cache-effekten har beaktats. naturligtvis kan det bara vara en annan version avfind
…) - @psmears Naturligtvis har jag gjort dessa tester flera gånger. Cachningproblemet har nämnts även i kommentarerna till frågan före det första svaret. Min
find
version är find (GNU findutils) 4.6.0 - Varför är det förvånande att lägga till
-name '*.txt'
find
? Det måste göra extra arbete, testa varje filnamn. - @Barmar Den ena sidan detta extra arbete kan göras extremt snabbt. Å andra sidan sparar detta extra arbete annat arbete.
find
måste skriva mindre data. Och att skriva till ett rör är en mycket långsammare operation. - Att skriva till en disk är mycket långsamt, att skriva till ett rör är inte så dåligt, det kopieras bara till en kärnbuffert. Lägg märke till att i ditt första test skrev du mer till
/dev/null
på något sätt mindre systemtid.
Svar
Observera : Jag antar att du menar find . -name filename
(annars letar du efter olika saker; find filename
tittar faktiskt på en sökväg som heter filnamn som kan innehålla nästan inga filer, och följaktligen avslutas riktigt snabbt).
Antag att du har en katalog med fem tusen filer. I de flesta filsystem lagras dessa filer faktiskt i en träd struktur , vilket gör det möjligt att snabbt hitta en viss fil.
Så när du frågar find
att hitta en fil vars namn bara kräver kontroll, find
frågar för den filen, och endast den filen, till det underliggande filsystemet, som kommer att läsa väldigt få sidor från masslagringen. Så om filsystemet är värt sitt salt kommer den här åtgärden att köras mycket snabbare än som går igenom hela trädet för att hämta alla poster.
När du ber om vanlig find
men det är exakt vad du gör, korsar du hela trädet och läser. Varje. Enkel. Inmatning. Med stora kataloger, detta kan vara ett problem (det är precis anledningen till att flera programvaror, som behöver lagra massor av filer på disken, kommer att skapa ”katalogträd” två eller tre komponenter djupt: på detta sätt behöver varje enskilt blad bara innehålla färre filer) .
Svar
Låt oss anta att filen / john / paul / george / ringo / beatles existerar och filen du söker efter kallas ”stenar”
find / stones
hitta kommer att jämföra ”beatles” med ”stenar” och släppa det när ”s” och ”b” inte matchar .
find / | grep stones
I det här fallet kommer find pass ”/ john / paul / george / ringo / beatles” till grep och grep wil Jag måste arbeta igenom hela vägen innan jag avgör om det är en matchning.
grep gör därför mycket mer arbete och det är därför det tar längre tid
Kommentarer
- Har du försökt det?
- Kostnaden för strängjämförelserna (extremt enkel och billig) är helt dvärgad av IO (eller bara syscall om cache) kostnad av katalogsökningarna.
- grep isn ’ ta strängjämförelse, dess jämförelse med reguljära uttryck vilket innebär att den måste arbeta sig igenom hela strängen tills den antingen hittar en match eller når slutet. Kataloguppsökningarna är desamma oavsett vad.
- @Paranoid Hm, vilken version av hitta pratar du om? Det ’ är uppenbarligen inte något som fyndet Jag ’ brukade vara i debian.
find filename
skulle bara returnerafilename
omfilename
inte var av typen katalog (eller var av typkatalog, men hade ingen post själv)