Grep w kilku tysiącach plików

13

Mam katalog zawierający około 26 000 plików i muszę grep w tych wszystkich plikach. Problem polega na tym, że potrzebuję go tak szybko, jak to możliwe, więc nie jest idealnym skryptem, w którym grep pobierze nazwę jednego pliku z polecenia find i zapisze dopasowania do pliku. Przed wydaniem „zbyt długiej listy argumentów” zajęło około 2 minut grep we wszystkich tych plikach. Wszelkie pomysły, jak to zrobić? edycja: istnieje skrypt, który cały czas tworzy nowe pliki, więc nie można umieścić wszystkich plików w różnych katalogach.

użytkownik2778979
źródło
1
używać findz xargslubgrep -R
Eddy_Em,
Działa dobrze, ale zajmuje 10 minut ...
user2778979,

Odpowiedzi:

19

Z find:

cd /the/dir
find . -type f -exec grep pattern {} +

( -type fjest wyszukiwanie tylko w zwykłych plikach (z wyłączeniem również dowiązań symbolicznych, nawet jeśli wskazują one na zwykłe pliki). Jeśli chcesz wyszukiwać w dowolnym typie plików oprócz katalogów (ale uważaj, istnieją pewne typy plików, takie jak fifos lub / dev / zero, które na ogół nie chcesz czytać), zamień -type fna GNU ! -xtype d( -xtype dpasuje do plików typu katalog po rozpoznaniu dowiązania symbolicznego)).

Z GNU grep:

grep -r pattern /the/dir

(ale uważaj, jeśli nie masz najnowszej wersji GNU grep, która będzie podążać za dowiązaniami symbolicznymi podczas schodzenia do katalogów). Nieregularne pliki nie będą wyszukiwane, chyba że dodasz -D readopcję. Najnowsze wersje GNU grepnadal nie będą jednak wyszukiwać wewnątrz dowiązań symbolicznych.

Bardzo stare wersje GNU findnie obsługiwały standardowej {} +składni, ale tam możesz użyć niestandardowej:

cd /the/dir &&
  find . -type f -print0 | xargs -r0 grep pattern

Występy prawdopodobnie będą związane z operacjami wejścia / wyjścia. To czas na wyszukiwanie byłby czasem potrzebnym do odczytania wszystkich danych z pamięci.

Jeśli dane znajdują się na nadmiarowej macierzy dyskowej, odczytywanie kilku plików jednocześnie może poprawić wydajność (i w przeciwnym razie może je pogorszyć). Jeśli wydajność nie jest związana z operacjami we / wy (ponieważ na przykład wszystkie dane znajdują się w pamięci podręcznej) i masz wiele procesorów, grepsmoże również pomóc współbieżność . Można to zrobić z GNU xargs„s -Popcja.

Na przykład, jeśli dane znajdują się w macierzy RAID1 z 3 dyskami lub jeśli dane znajdują się w pamięci podręcznej i masz 3 procesory, których czas oszczędzić:

cd /the/dir &&
  find . -type f -print0 | xargs -n1000 -r0P3 grep pattern

(tutaj za pomocą -n1000odradzania nowego grepco 1000 plików, do 3 równolegle działających jednocześnie).

Należy jednak pamiętać, że jeśli dane wyjściowe grepzostaną przekierowane, otrzymamy źle przeplecione dane wyjściowe z 3 grepprocesów, w którym to przypadku możesz chcieć uruchomić je jako:

find . -type f -print0 | stdbuf -oL xargs -n1000 -r0P3 grep pattern

(w najnowszym systemie GNU lub FreeBSD) lub użyj --line-bufferedopcji GNU grep.

Jeśli patternjest to ciąg stały, dodanie -Fopcji może poprawić sprawy.

Jeśli nie są to dane wielobajtowe lub jeśli chodzi o dopasowanie tego wzorca, nie ma znaczenia, czy dane są znakiem wielobajtowym, czy nie:

cd /the/dir &&
  LC_ALL=C grep -r pattern .

może znacznie poprawić wydajność.

Jeśli często przeprowadzasz takie wyszukiwania, możesz zindeksować swoje dane przy użyciu jednej z wielu wyszukiwarek.

Stéphane Chazelas
źródło
3

26000 plików w jednym katalogu to dużo dla większości systemów plików. Prawdopodobnie znaczna część czasu zajmuje czytanie tego dużego katalogu. Rozważ podzielenie go na mniejsze katalogi zawierające tylko kilkaset plików.

Połączenia findnie mogą wyjaśnić słabej wydajności, chyba że zrobisz to źle. Jest to szybki sposób na przejrzenie katalogu i upewnienie się, że nie ryzykujesz próby wykonania zbyt długiego wiersza poleceń. Upewnij się, że używasz tego -exec grep PATTERN {} +, który pakuje tyle plików, ile może na wywołanie polecenia, a nie -exec grep PATTERN {} \;, który wykonuje się grepraz na plik: wykonanie polecenia raz na plik może być znacznie wolniejsze.

Gilles „SO- przestań być zły”
źródło
Dzięki, zrobię coś z Google i prawdopodobnie podzielę to. Zrobiłem dokładnie to, o czym piszesz, i zajęło to 3 razy dłużej niż tylko grep ...
user2778979,
Gilles, czy mówisz, że wydajność różni się znacznie dla 26 000 plików w jednym katalogu w porównaniu do 26 000 plików rozproszonych w, powiedzmy, 100 katalogach?
user001
1
@ user001 Tak. Różnice między nimi zależą od systemu plików i być może podstawowej pamięci, ale spodziewałbym się, że każdy system plików będzie mierzalnie szybszy z 260 plikami w każdym ze 100 katalogów w porównaniu z 26000 plików w jednym katalogu.
Gilles „SO- przestań być zły”
Dziękuję za wyjaśnienie. Zadałem pytanie uzupełniające w tej sprawie, aby zrozumieć podstawę rozbieżności.
user001
0

Jeśli musisz grepować WSZYSTKIE pliki wiele razy (jak powiedziałeś, uruchamiając skrypt) sugerowałbym zajrzenie do dysków RAM, skopiowanie wszystkich plików tam, a następnie wielokrotne grepowanie plików, to przyspieszy twoje wyszukiwanie o współczynnik co najmniej 100x.

Potrzebujesz tylko wystarczającej ilości pamięci RAM. W przeciwnym razie powinieneś zajrzeć do indeksowania plików, np. do bazy danych Lucene lub nosql, a następnie uruchamianie zapytań w tej sprawie.

Tobias Feldballe
źródło
Jak wspomniano w innym miejscu, nie pomaga to w tym, że istnieje zbyt wiele plików, aby uruchomić grep. Jest też taki punkt, że: „istnieje skrypt, który cały czas tworzy nowe pliki, więc nie można umieszczać wszystkich plików w różnych katalogach”.
Jeff Schaller
-2

Wszystkie pliki w katalogu

grep 'search string' *

z rekurencyjnie

grep -R 'search string' *
Markus
źródło
Chcesz opracować -1?
Markus,
4
Nie przegłosowałem, ale jest kilka problemów z twoim: OP wspomniał o „zbyt długiej liście argumentów”, której twój pierwszy nie naprawi i prawdopodobnie robił to wcześniej. Drugi nie pomaga w tym względzie (pomógłby, gdybyś użył .zamiast niego *). *wyklucza pliki kropkowe (choć z opcją -R, a nie te w katalogach cyklicznych). -R w przeciwieństwie do -r podąża za dowiązaniami symbolicznymi nawet w najnowszych wersjach GNU grep. Będziesz także mieć problem z plikami w bieżącym katalogu, których nazwa zaczyna się na-
Stéphane Chazelas,