Wypróbowałem oba polecenia, a polecenie find | grep "filename"
jest wiele razy wolniejsze niż proste find "filename"
.
Jakie byłoby właściwe wyjaśnienie tego zachowania?
Komentarze
- Ty wypisują każdy plik za pomocą polecenia find, a następnie przekazują dane do przetwarzania grep. W przypadku użycia funkcji find ' jako własnego, brakuje kroku przekazywania każdego wymienionego pliku do programu grep w celu przeanalizowania wyniku. Będzie to zatem szybsze.
- W jakim sensie wolniej? Czy wykonanie poleceń zajmuje trochę czasu?
- Nie mogę ' odtworzyć tego lokalnie. Jeśli już,
time find "$HOME" -name '.profile'
zgłasza dłuższy czas niżtime find "$HOME" | grep -F '.profile'
. (17s vs 12s). - @JenniferAnderson Prowadziłem oba wielokrotnie. 17 i 12 sekund to średnie. I tak, odmiana
grep
będzie pasować w dowolnym miejscu wynikufind
, natomiast dopasowanie zfind -name
będzie pasować tylko dokładnie (w tym przypadku). - Tak,
find filename
byłoby szybkie . W pewnym sensie założyłem, że to pomyłka i że OP oznaczałfind -name filename
. Zfind filename
, tylkofilename
zostanie zbadany (i nic więcej).
Odpowiedz
(Zakładam, że GNU find
tutaj)
Używając tylko
find filename
byłoby szybkie, ponieważ zwróciłoby po prostu filename
lub nazwy wewnątrz filename
, jeśli jest to katalog, lub błąd, jeśli ta nazwa nie istnieje w bieżącym katalogu. Jest to bardzo szybka operacja, podobna do ls filename
(ale rekurencyjna, jeśli filename
jest katalogiem).
W Natomiast
find | grep filename
pozwoliłoby find
wygenerować listę wszystkich nazwisk z bieżący katalog i poniżej, który grep
będzie filtrował. To oczywiście byłaby znacznie wolniejsza operacja.
Zakładam, że to, co faktycznie zamierzone było
find . -type f -name "filename"
To wyszukałoby filename
jako nazwę zwykłego pliku w dowolnym miejscu w bieżący katalog lub niższy.
Będzie to równie szybkie (lub porównywalnie szybkie) jak find | grep filename
, ale grep
rozwiązanie dopasowałoby filename
do pełnej ścieżki każdej znalezionej nazwy, podobnie jak -path "*filename*"
zrobiłby z find
.
Zamieszanie wynika z niezrozumienia sposobu, w jaki find
działa.
Narzędzie pobiera kilka ścieżek i zwraca wszystkie nazwy znajdujące się pod tymi ścieżkami.
Następnie możesz ogranicz zwracane nazwy za pomocą różnych testów, które mogą działać na nazwie pliku, ścieżce, sygnaturze czasowej, rozmiarze pliku, typie pliku itp.
Kiedy mówisz
find a b c
pytasz find
o wyświetlenie wszystkich nazw dostępnych w trzech ścieżkach a
, b
i c
. Jeśli są to nazwy zwykłych plików w bieżącym katalogu, zostaną one zwrócone. Jeśli któryś z nich jest nazwą katalogu, zostanie zwrócony wraz ze wszystkimi innymi nazwami w tym katalogu.
Kiedy to zrobię
find . -type f -name "filename"
Generuje listę wszystkich nazw w bieżącym katalogu (.
) i poniżej. Następnie ogranicza nazwy do zwykłych plików, tj. Nie do katalogów itp., Z -type f
. Następnie istnieje dalsze ograniczenie do nazw, które pasują do filename
, używając -name "filename"
. Ciąg filename
może być wzorcem globalnym w nazwie pliku, takim jak *.txt
(pamiętaj tylko o zacytowaniu!).
Przykład:
Wydaje się, że następujące polecenie „znajduje” plik o nazwie .profile
w moim katalogu domowym:
$ pwd /home/kk $ find .profile .profile
Ale w rzeczywistości zwraca wszystkie nazwy ze ścieżki .profile
(jest tylko jedna nazwa i jest to ten plik).
Następnie cd
o jeden poziom wyżej i próbuję ponownie:
$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory
find
polecenie nie może teraz znaleźć żadnej ścieżki o nazwie .profile
.
Jeśli jednak popatrzę na bieżący katalog, a następnie ograniczę zwracane nazwy tylko do .profile
, znajdzie stamtąd również:
$ pwd /home $ find . -name ".profile" ./kk/.profile
Komentarze
Odpowiedź
Nietechniczne wyjaśnienie: Poszukiwanie Jacka w tłumie jest szybszy niż szukanie wszystkich w tłumie i eliminowanie wszystkich z wyjątkiem Jacka.
Komentarze
- Problem polega na tym, że OP oczekuje, że Jack bądź jedyną osobą w tłumie. Jeśli tak, ' mają szczęście.
find jack
wyświetlijack
jeśli ' to plik o nazwiejack
lub wszystkie nazwy w katalogu, jeśli jest to katalog ' sa. To ' to niezrozumienie, jak działafind
.
Odpowiedź
Jeszcze nie zrozumiałem problemu, ale mogę podać więcej informacji.
Podobnie jak w przypadku Kusalanandy połączenie find | grep
jest wyraźnie szybszy w moim systemie, co nie ma większego sensu. Na początku założyłem jakiś problem z buforowaniem; że zapis do konsoli spowalnia czas do następnego wywołania systemowego w celu odczytania nazwy następnego pliku. Zapis do potoku jest bardzo szybki: około 40 MiB / s nawet dla zapisów 32-bajtowych (na moim raczej wolnym systemie; 300 MiB / s dla bloku o rozmiarze 1 MiB). Dlatego założyłem, że find
może szybciej czytać z systemu plików podczas zapisywania do potoku (lub pliku), tak że dwie operacje odczytu ścieżek plików i zapisu do konsoli mogą działać równolegle ( czego find
jako proces pojedynczego wątku nie może wykonać samodzielnie.
To find
„błąd”
Porównanie dwóch wywołań
:> time find "$HOME"/ -name "*.txt" >/dev/null real 0m0.965s user 0m0.532s sys 0m0.423s
i
:> time find "$HOME"/ >/dev/null real 0m0.653s user 0m0.242s sys 0m0.405s
pokazuje, że find
robi coś niesamowicie głupiego (cokolwiek to może być). Po prostu okazuje się całkiem niekompetentny w wykonywaniu -name "*.txt"
.
Może zależeć od stosunku wejścia / wyjścia
Można by pomyśleć, że find -name
wygrywa, jeśli jest bardzo mało do napisania. Ale to staje się po prostu bardziej krępujące dla find
. Traci, nawet jeśli w ogóle nie ma nic do napisania wobec 200 tys. plików (13 mln potoków) dla grep
:
time find /usr -name lwevhewoivhol
find
może być tak szybkie, jak grep
, chociaż
Okazuje się, że find
„głupota z name
nie obejmuje innych testów. Zamiast tego użyj wyrażenia regularnego i problem zniknie:
:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s
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
Komentarze
- Jak powtarzalne są twoje czasy? Jeśli najpierw wykonałeś test
-name
, mógł być wolniejszy z powodu braku buforowania zawartości katalogu. (Podczas testowania-name
i-regex
stwierdzam, że zajmują mniej więcej tyle samo czasu, przynajmniej po uwzględnieniu efektu pamięci podręcznej. oczywiście, może to być po prostu inna wersjafind
…) - @psmears Oczywiście kilka razy przeprowadzałem te testy. O problemie buforowania wspomniano nawet w komentarzach do pytania przed pierwszą odpowiedzią. Moja
find
wersja to find (GNU findutils) 4.6.0 - Dlaczego to zaskakujące, że dodawanie
-name '*.txt'
zwalniafind
? Musi wykonać dodatkową pracę, testując każdą nazwę pliku. - @Barmar Z jednej strony ta dodatkowa praca może być wykonana bardzo szybko. Z drugiej strony ta dodatkowa praca oszczędza inną pracę.
find
musi zapisać mniej danych. A zapis do potoku jest znacznie wolniejszą operacją. - Zapis na dysku jest bardzo wolny, zapis do potoku nie jest taki zły, po prostu kopiuje do bufora jądra. Zauważ, że w pierwszym teście pisanie więcej do
/dev/null
w jakiś sposób zużywa mniej czasu systemowego.
Odpowiedź
Uwaga : Zakładam, że masz na myśli find . -name filename
(w przeciwnym razie „szukasz różnych rzeczy; find filename
w rzeczywistości szuka ścieżki o nazwie nazwa pliku , może zawierać prawie żadnych plików, więc kończy się bardzo szybko).
Załóżmy, że masz katalog zawierający pięć tysięcy plików. W większości systemów plików te pliki są w rzeczywistości przechowywane w strukturze drzewa , co pozwala na szybkie zlokalizowanie dowolnego pliku.
Kiedy więc poprosisz find
o zlokalizowanie pliku, którego nazwa wymaga tylko sprawdzenia, find
zapyta dla tego pliku, i tylko tego pliku, do bazowego systemu plików, który odczyta bardzo niewiele stron z pamięci masowej. Więc jeśli system plików jest wart swojej soli, ta operacja będzie przebiegać znacznie szybciej niż przechodzenie przez całe drzewo w celu pobrania wszystkich wpisów.
Kiedy prosisz o zwykły find
, ale to właśnie „właśnie to robisz, przechodzisz przez całe drzewo, czytając. Każdy. Pojedynczy. Wpis. Przy dużych katalogach, może to być problem (jest to dokładnie powód, dla którego kilka programów, które muszą przechowywać dużo plików na dysku, utworzy „drzewa katalogów” o głębokości dwóch lub trzech elementów: w ten sposób każdy liść musi przechowywać tylko mniej plików) .
Odpowiedź
Załóżmy, że plik / john / paul / george / ringo / beatles istnieje i plik, którego szukasz nazywa się „kamienie”
find / stones
find porówna „beatles” z „kamieniami” i upuści go, gdy „s” i „b” nie pasują .
find / | grep stones
W tym przypadku find przekaże „/ john / paul / george / ringo / beatles” do grep i grep wil Muszę przejść przez całą ścieżkę, zanim określę, czy pasuje.
Dlatego grep wykonuje znacznie więcej pracy, dlatego zajmuje to więcej czasu.
Komentarze
- Czy już próbowałeś?
- Koszt porównań ciągów (niezwykle prosty i tani) jest całkowicie przyćmiony przez IO (lub po prostu wywołanie systemowe, jeśli jest buforowane) przeszukiwania katalogów.
- grep isn ' ta porównanie ciągów, porównanie wyrażeń regularnych, co oznacza, że musi przejść przez cały ciąg, dopóki nie znajdzie mecz lub dobiegnie końca. Wyszukiwania katalogów są takie same bez względu na wszystko.
- @Paranoid Hm, o jakiej wersji find mówisz? To ' najwyraźniej nie jest czymś takim, jak find ja ' używany w Debianie.
find filename
zwróci tylkofilename
, jeślifilename
nie był typu katalog (lub był typu katalog, ale sam nie ma żadnego wpisu)