Znaleźć podciąg w plikach w podkatalogach za pomocą jednego wbudowanego polecenia?

10

W systemie Windows, gdybym chciał znaleźć ciąg znaków we wszystkich plikach we wszystkich podkatalogach, zrobiłbym coś takiego

findstr /C:"the string" /S *.h

Jednak w systemie Linux (powiedzmy, Ubuntu) znalazłem innego sposobu niż niektóre rurami polecenia udziałem find, xargsoraz grep(przykładem jest na tej stronie: ? Jak mogę rekursywnie grep poprzez podkatalogów ). Moje pytanie jest jednak inne: czy jest jakieś wbudowane polecenie, które działa przez tę magię, bez konieczności pisania skryptu powłoki?

Guido Domenici
źródło

Odpowiedzi:

19

GNU grep pozwala na rekurencyjne wyszukiwanie w podkatalogach:

grep -r --include='*.h' 'the string' .
machać
źródło
Wypróbowałem dokładnie ten wiersz poleceń w Ubuntu, ale otrzymałem „grep: nieprawidłowa opcja -„ M ””, chociaż nigdzie nie widzę żadnego „M” ... zagadkowe
Guido Domenici
@Guido działa tutaj dobrze
phunehehe
W sugerowanej edycji TomasG zaleca zmianę ostatniego *na '*': „Aby uniknąć błędów, gdy nazwa pliku zaczyna się od -”, należy podać ostatni znak zastępczy - ”
Michael Mrozek
Dziwny zbieg wydarzeń, teraz działa również dla mnie, jak podano w pierwotnej odpowiedzi. Dzięki!
Guido Domenici
1
@Guido: Przyczyną problemu może być plik w bieżącym katalogu o nazwie -Msomethinglub GREP_OPTIONSustawienie.
Gilles „SO- przestań być zły”
2

grep -r searchpattern /path/to/start/in

Gdzie /path/to/start/in/może być tylko „ .” dla bieżącego katalogu.

mattdm
źródło
1

Nie. find -name \*.h -print0 | xargs -0 grep -l 'the regex'Jest tak magiczna, jak to tylko możliwe.

Glenn Jackman
źródło
GNU grep ma wbudowane wspólne przypadki ze swoją -ropcją. Ciężka artyleria nie potrzebuje.
Gilles 'SO - przestań być zły'
3
xargsdodaje tylko hałas. Użyjfind -name \*.h -execdir grep -l 'the regex {} +
użytkownik nieznany
0

czy jest jakieś wbudowane polecenie, które działa dzięki tej magii ...?

Mówiąc pedantycznie, nie, nie można zakładać, że takie polecenie istnieje .

Istnieje wiele różnych implementacji Uniksa, a każda z nich ma swoje inne dziwactwa. POSIX, wspólny mianownik (i najbliższy standardowi w Unices) nie określa takiej opcji dlagrep .

Jak wspomniano w innych odpowiedziach, implementacja GNU grepma niestandardową opcję, która robi to, co chcesz. Chociaż ta konkretna implementacja może być powszechna w systemach Linux, nie można zakładać jej dostępności w żadnym systemie Unix, nawet w niektórych systemach Linux.

Na koniec powinienem wspomnieć, że filozofią Uniksa jest faworyzowanie kombinacji kilku prymitywnych programów, zamiast korzystania z jednego dużego monolitycznego pliku wykonywalnego, który próbuje zrobić wszystko na raz.

W twoim przypadku przeszukiwanie systemu plików i dopasowanie wyrażenia regularnego w strumieniu to dwa osobne zadania. Każdy jest traktowany osobno w osobnym programie.

rahmu
źródło
0

Aby znaleźć ciąg z danego katalogu, użyj poniższej komendy

find <fullDirectoryPath> -name '*' -exec grep -l '<StringToFind>' {} \;

Na przykład:

find /apps_bev/apps/xfer/export/02210 -name '*' -exec grep -l '38221000001032' {} \;
Jogesh
źródło
1
grepmoże przyjmować więcej niż jeden plik jako argument, więc powinieneś użyć +zamiast, \;aby uniknąć uruchamiania jednego grepwywołania na plik, co jest dość nieefektywne.
Stéphane Chazelas,
1
Należy pamiętać, że -name '*'ogranicza się do plików, których nazwa jest poprawnym tekstem w bieżących ustawieniach regionalnych ( findprzynajmniej w niektórych implementacjach), ale inne komponenty katalogu mogą nadal zawierać sekwencje bajtów, które nie tworzą prawidłowych znaków. Jeśli Twoim celem -name '*'było upewnienie się, że wynik jest prawidłowy (pomijając pliki o niepoprawnych nazwach), wolisz użyć find ... ! -name '*' -prune -o -exec grep ... {} +, który również przestałby findschodzić do katalogów o niepoprawnych nazwach.
Stéphane Chazelas,