Które jest bardziej skuteczne w wyszukiwaniu, które pliki w całym systemie plików zawierają ciąg znaków: rekurencyjny grep lub znajdź za pomocą grep w instrukcji exec? Zakładam, że znajdowanie byłoby bardziej wydajne, ponieważ możesz przynajmniej przeprowadzić filtrowanie, jeśli znasz rozszerzenie pliku lub wyrażenie regularne pasujące do nazwy pliku, ale kiedy wiesz tylko, -type f
która z nich jest lepsza? GNU grep 2.6.3; find (GNU findutils) 4.4.2
Przykład:
grep -r -i 'the brown dog' /
find / -type f -exec grep -i 'the brown dog' {} \;
-exec {} +
formularz będzie mniej widelców, więc powinien być szybszy niż-exec {} \;
. Konieczne może być dodanie-H
(lub-h
)grep
opcji, aby uzyskać dokładnie równoważny wynik.-r
opcjęgrep
dla drugiegoOdpowiedzi:
Nie jestem pewny:
to naprawdę to, co miałeś na myśli. Oznaczałoby to rekurencyjnie grep we wszystkich nie ukrytych plikach i katalogach w
/
(ale nadal zaglądanie do ukrytych plików i katalogów wewnątrz nich).Zakładając, że miałeś na myśli:
Kilka rzeczy do zapamiętania:
grep
implementacje obsługują-r
. A wśród tych, które się tak zachowują, zachowania się różnią: niektóre podążają za dowiązaniami symbolicznymi do katalogów podczas przechodzenia przez drzewo katalogów (co oznacza, że możesz skończyć przeglądać kilka razy w tym samym pliku lub nawet działać w nieskończonych pętlach), niektóre nie. Niektóre zaglądają do plików urządzeń (/dev/zero
na przykład zajmie to trochę czasu ) lub potoków lub plików binarnych ... niektóre nie.grep
zaczyna przeszukiwać pliki, gdy tylko je odkryje. Ale gdy szuka w pliku, nie szuka już więcej plików do przeszukania (co w większości przypadków jest prawdopodobnie równie dobre)Twój:
(usunięto to,
-r
co nie miało sensu tutaj) jest strasznie nieefektywne, ponieważ uruchamiasz jedengrep
na plik.;
powinien być używany tylko dla poleceń, które akceptują tylko jeden argument. Ponadto tutaj, ponieważgrep
wygląda tylko w jednym pliku, nie wydrukuje nazwy pliku, więc nie będziesz wiedział, gdzie są dopasowania.Nie przeglądasz plików urządzeń, potoków, dowiązań symbolicznych ..., nie podążasz za dowiązaniami symbolicznymi, ale nadal potencjalnie zaglądasz do takich rzeczy jak
/proc/mem
.byłoby znacznie lepiej, ponieważ
grep
uruchomiono by jak najmniej poleceń. Otrzymasz nazwę pliku, chyba że ostatnie uruchomienie zawiera tylko jeden plik. W tym celu lepiej użyć:lub z GNU
grep
:Pamiętaj, że
grep
nie zostanie uruchomiony, dopókifind
nie znajdzie wystarczającej liczby plików do przeżuwania, więc wystąpi pewne początkowe opóźnienie. Ifind
nie będzie kontynuował wyszukiwania kolejnych plików, dopóki poprzedniegrep
nie powróci. Przydzielanie i przekazywanie dużej listy plików ma pewien (prawdopodobnie nieistotny) wpływ, więc w sumie prawdopodobnie będzie mniej wydajne niż to,grep -r
że nie podąża za dowiązaniem symbolicznym ani nie przegląda urządzeń.Za pomocą narzędzi GNU:
Jak wyżej,
grep
uruchomionychfind
zostanie jak najmniej instancji, ale będzie ona nadal szukała więcej plików, podczas gdy pierwszegrep
wywołanie zajrzy do pierwszej partii. To może, ale nie musi być zaletą. Na przykład dane przechowywane na obrotowych dyskach twardychfind
igrep
uzyskiwanie dostępu do danych przechowywanych w różnych miejscach na dysku spowolnią przepustowość dysku, powodując ciągłe ruchy głowicy dysku. W konfiguracji RAID (gdziefind
igrep
może uzyskiwać dostęp do różnych dysków) lub na dyskach SSD może to mieć pozytywny wpływ.W konfiguracji RAID, bieganie kilka jednoczesnych
grep
wywołania może również poprawić rzeczy. Nadal z narzędziami GNU na macierzy RAID1 z 3 dyskami,może znacznie zwiększyć wydajność. Zauważ jednak, że drugi
grep
zostanie uruchomiony dopiero po znalezieniu wystarczającej liczby plików do wypełnienia pierwszegogrep
polecenia. Możesz dodać-n
opcjęxargs
, aby stało się to wcześniej (i przekazać mniej plików na jednogrep
wywołanie).Zauważ też, że jeśli przekierowujesz
xargs
dane wyjściowe na cokolwiek innego niż urządzenie końcowe,greps
s zacznie buforować swoje dane wyjściowe, co oznacza, że dane wyjściowe tychgrep
prawdopodobnie zostaną nieprawidłowo przeplecione. Będziesz musiał użyć na nichstdbuf -oL
(jeśli jest dostępny, jak na GNU lub FreeBSD), aby obejść ten problem (nadal możesz mieć problemy z bardzo długimi liniami (zazwyczaj> 4KiB)) lub poproś każde z nich o zapisanie ich wyników w osobnym pliku i połączenie ich. wszystko w końcu.Tutaj ciąg, którego szukasz, jest naprawiony (nie jest wyrażeniem regularnym), więc użycie tej
-F
opcji może mieć znaczenie (mało prawdopodobne, ponieważgrep
implementacje wiedzą, jak to zoptymalizować).Inną rzeczą, która może mieć dużą różnicę, jest ustawienie języka na C, jeśli jesteś w ustawieniu wielobajtowym:
Aby uniknąć zaglądania do wnętrza
/proc
,/sys
... użyj-xdev
i określ systemy plików, w których chcesz wyszukiwać:Lub przycinaj ścieżki, które chcesz jawnie wykluczyć:
źródło
-exec
orzeczenia na stronie podręcznika SolarisJeśli
*
wgrep
wywołaniu nie jest dla ciebie ważne to pierwszy powinien być bardziej efektywny, jak tylko jedna instancjagrep
jest uruchomiona, i widły nie są wolne. W większości przypadków będzie to szybsze, nawet*
w skrajnych przypadkach sortowanie może to odwrócić.Mogą istnieć inne
find
-grep
struktury, które działają lepiej, zwłaszcza w przypadku wielu małych plików. Odczytywanie dużych ilości wpisów plików i i-węzłów jednocześnie może poprawić wydajność obracających się mediów.Ale spójrzmy na statystyki syscall:
odnaleźć
tylko grep
źródło
-r
flagęgrep
podczas używaniafind
. Możesz zobaczyć, że wielokrotnie przeszukiwał te same pliki, porównując ich liczbęopen
.-r
powinno być nieszkodliwe, ponieważ-type f
gwarancje, że żaden argument nie jest katalogiem. Wiele z nichopen()
jest bardziej prawdopodobne w stosunku do innych plików otwieranychgrep
przy każdym wywołaniu (biblioteki, dane lokalizacji ...) (dzięki za edycję mojej odpowiedzi btw)Jeśli korzystasz z dysku SSD i czas poszukiwania jest znikomy, możesz użyć GNU równolegle:
Spowoduje to wykonanie do 8 procesów grep jednocześnie, w zależności od tego, co
find
znaleziono.Spowoduje to uszkodzenie dysku twardego, ale dysk SSD powinien sobie z tym poradzić.
źródło
Jeszcze jedna rzecz do rozważenia w tej sprawie jest następująca.
Czy którykolwiek z katalogów, przez które grep będzie musiał przechodzić rekurencyjnie, będzie zawierał więcej plików niż ustawienie nofile w twoim systemie ? (np. liczba otwartych uchwytów plików, domyślnie jest to 1024 w większości dystrybucji Linuksa)
Jeśli tak, to zdecydowanie jest droga do znalezienia, ponieważ niektóre wersje grep będą bombardować zbyt długim błędem listy argumentów, gdy trafi do katalogu z większą liczbą plików niż ustawienie maksymalnej liczby otwartych uchwytów plików.
Tylko moje 2 ¢.
źródło
grep
bombardować? Przynajmniej z GNU grep, jeśli podasz ścieżkę z trailingiem/
i użyjesz-R
jej, po prostu przejdzie przez katalogi. Powłoka nie będzie się rozwijać coś chyba dasz shell-globs. Tak więc w podanym przykładzie (/*
) tylko treść/
materii, a nie podfolderów, które zostaną po prostu wyliczonegrep
, nie jest przekazywana jako argument z powłoki.