Próbowałem obu poleceń, a polecenie find | grep 'filename'
jest wiele razy wolniejsze niż proste find 'filename'
polecenie.
Jakie byłoby właściwe wytłumaczenie tego zachowania?
command-line
grep
find
search
file-search
yoyo_fun
źródło
źródło
time find "$HOME" -name '.profile'
zgłasza dłuższy czas niżtime find "$HOME" | grep -F '.profile'
. (17s vs. 12s).grep
odmiana będzie pasować w dowolnym miejscufind
wyniku, podczas gdy dopasowanie zfind -name
pasowałoby tylko dokładnie (w tym przypadku).find filename
byłoby szybko . Przyjąłem, że to była literówka i że OP miał na myślifind -name filename
. Zfind filename
, tylkofilename
zostanie zbadane (i nic więcej).Odpowiedzi:
(Zakładam, że GNU
find
tutaj)Używam tylko
byłoby szybkie, ponieważ zwróciłoby się po prostu
filename
, lub nazwy w środku,filename
jeśli jest to katalog, lub błąd, jeśli ta nazwa nie istniała w bieżącym katalogu. Jest to bardzo szybka operacja, podobna dols filename
(ale rekurencyjna, jeślifilename
jest katalogiem).W przeciwieństwie,
pozwoli
find
wygenerować listę wszystkich nazw z bieżącego katalogu i poniżej, któregrep
następnie zostaną odfiltrowane. Byłoby to oczywiście znacznie wolniejsze działanie.Zakładam, że to, co faktycznie było zamierzone, było
Będzie to wyglądało
filename
jak nazwa zwykłego pliku w dowolnym miejscu w bieżącym katalogu lub poniżej.Będzie to tak szybkie (lub porównywalnie szybkie), jak
find | grep filename
, alegrep
rozwiązanie będzie pasowaćfilename
do pełnej ścieżki każdej znalezionej nazwy, podobnie do tego-path '*filename*'
, co by to zrobiłofind
.Zamieszanie wynika z niezrozumienia sposobu
find
działania.Narzędzie pobiera wiele ścieżek i zwraca wszystkie nazwy poniżej tych ścieżek.
Następnie możesz ograniczyć zwracane nazwy za pomocą różnych testów, które mogą oddziaływać na nazwę pliku, ścieżkę, znacznik czasu, rozmiar pliku, typ pliku itp.
Kiedy powiesz
poprosisz
find
o podanie wszystkich nazw dostępnych w ramach trzech ścieżeka
,b
orazc
. Jeśli są to nazwy zwykłych plików w bieżącym katalogu, zostaną one zwrócone. Jeśli którykolwiek z nich jest nazwą katalogu, zostanie on zwrócony wraz ze wszystkimi dalszymi nazwami w tym katalogu.Kiedy robię
Generuje to listę wszystkich nazw w bieżącym katalogu (
.
) i poniżej. Następnie ogranicza nazwy do zwykłych plików, tj. Nie katalogów itp-type f
. Za pomocą . Następnie istnieje dalsze ograniczenie nazw, które pasująfilename
przy użyciu-name 'filename'
. Ciągfilename
może być wzorcem globowania nazw plików, takim jak*.txt
(pamiętaj, żeby go zacytować!).Przykład:
Następujące zdaje się „znajdować” plik wywołany
.profile
w moim katalogu domowym:Ale w rzeczywistości zwraca wszystkie nazwy na ścieżce
.profile
(jest tylko jedna nazwa, i to z tego pliku).Następnie
cd
przechodzę na wyższy poziom i próbuję ponownie:find
Komenda teraz nie mogę znaleźć żadnej ścieżki nazwie.profile
.Jeśli jednak popatrzę na bieżący katalog, a następnie ograniczę tylko zwrócone nazwy
.profile
, znajdzie je również stamtąd:źródło
find filename
zwróci tylko,filename
jeślifilename
nie byłby katalogiem typu (lub byłby katalogiem typu, ale sam nie miał żadnego wpisu)Wyjaśnienie nietechniczne: Szukanie Jacka w tłumie jest szybsze niż szukanie wszystkich w tłumie i eliminowanie wszystkich z wyjątkiem Jacka.
źródło
find jack
wyświetli listę,jack
jeśli jest to plik o nazwiejack
, lub wszystkie nazwy w katalogu, jeśli jest to katalog. To nieporozumienie, jak tofind
działa.Nie zrozumiałem jeszcze problemu, ale mogę dostarczyć więcej informacji.
Podobnie jak w przypadku Kusalanandy,
find | grep
połączenie jest wyraźnie szybsze w moim systemie, co nie ma większego sensu. Początkowo przyjąłem problem buforowania; zapisywanie na konsoli spowalnia czas do następnego wywołania systemowego w celu odczytania nazwy następnego pliku. Pisanie do potoku jest bardzo szybkie: około 40 Mb / s nawet w przypadku zapisu 32-bajtowego (w moim raczej wolnym systemie; 300 MiB / s dla bloku o wielkości 1 Mb). W związku z tym założyłem, żefind
można szybciej czytać z systemu plików podczas zapisywania do potoku (lub pliku), aby dwie operacje odczytujące ścieżki plików i zapisujące do konsoli mogły działać równolegle (czegofind
jako proces pojedynczego wątku nie może wykonać samodzielnie.To
find
winaPorównywanie dwóch połączeń
i
pokazuje, że
find
robi coś niesamowicie głupiego (cokolwiek to może być). Po prostu okazuje się, że jest dość niekompetentny w wykonywaniu-name '*.txt'
.Może zależeć od stosunku wejścia / wyjścia
Możesz pomyśleć, że
find -name
wygrywa, jeśli jest bardzo mało do napisania. Ale jest coraz bardziej zawstydzającefind
. Traci nawet, jeśli nie ma nic do zapisania w stosunku do 200 000 plików (13 mln danych potoku) dlagrep
:find
może być jak najszybciejgrep
, choćOkazuje się, że
find
głupotaname
nie obejmuje innych testów. Zamiast tego użyj wyrażenia regularnego, a problem zniknął:Myślę, że można to uznać za błąd. Czy ktoś chce zgłosić błąd? Moja wersja to find (GNU findutils) 4.6.0
źródło
-name
test, być może był on wolniejszy z powodu braku buforowania zawartości katalogu. (Podczas testowania-name
i-regex
znajdę biorą mniej więcej tyle samo czasu, co najmniej raz efekt pamięci podręcznej zostało uwzględnione Oczywiście może to tylko inna wersja.find
...)find
wersja to find (GNU findutils) 4.6.0-name '*.txt'
spowalniafind
? Musi wykonać dodatkową pracę, testując każdą nazwę pliku.find
musi pisać mniej danych. A pisanie na fajce jest znacznie wolniejszą operacją./dev/null
jakiś sposób zużywa mniej czasu systemowego.Uwaga : Zakładam, że masz na myśli
find . -name filename
(w przeciwnym razie szukasz różnych rzeczy;find filename
faktycznie szuka ścieżki o nazwie nazwa_pliku , która może nie zawierać prawie żadnych plików, a zatem wychodzi bardzo szybko).Załóżmy, że masz katalog zawierający pięć tysięcy plików. W większości systemów plików pliki te są faktycznie przechowywane w strukturze drzewa , co pozwala szybko zlokalizować dowolny plik.
Więc kiedy pytasz
find
, aby zlokalizować plik, którego nazwa wymaga jedynie sprawdzenie,find
będą prosić o tym pliku, a jedynie, że plik, do systemu plików bazowych, które będą czytać bardzo kilka stron z pamięci masowej. Jeśli więc system plików jest wart swojej soli, ta operacja będzie przebiegać znacznie szybciej niż przemierzanie całego drzewa w celu pobrania wszystkich wpisów.Kiedy prosisz o proste,
find
jednak dokładnie to robisz, przemierzasz całe drzewo, czytając. Każdy. Pojedynczy. Wejście. W przypadku dużych katalogów może to stanowić problem (jest to dokładnie powód, dla którego kilka programów, które muszą przechowywać wiele plików na dysku, utworzy „drzewa katalogów” o głębokości dwóch lub trzech składników: w ten sposób każdy liść musi zawierać tylko mniej akta).źródło
Załóżmy, że istnieje plik / john / paul / george / ringo / beatles, a szukany plik nazywa się „kamieniami”
find porównuje „beatles” do „stones” i upuszcza go, gdy „s” i „b” nie pasują.
W tym przypadku find przejdzie „/ john / paul / george / ringo / beatles” do grep i grep będzie musiał przejść przez całą ścieżkę przed ustaleniem, czy pasuje.
grep wykonuje zatem znacznie więcej pracy, dlatego zajmuje więcej czasu
źródło