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 än time 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 i find -resultatet, medan matchning med find -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 menade find -name filename. Med find filename skulle endast filename 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

  • find filename skulle bara returnera filename om filename inte var av typen katalog (eller var av typkatalog, men hade ingen post själv)

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 listar jack om det ’ en fil som heter jack, eller alla namn i katalogen om det ’ är en katalog. Det ’ är ett missförstånd om hur find 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 av find …)
  • @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.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *