Jak wyszukać ciąg w pliku PHP za pomocą `grep`?

11

Szukam deklaracji klasy na stronie z setkami plików PHP. Jak mogę to zrobić w bieżącym folderze i podfolderach za pomocą grep ?

Przetestowałem cding do folderu, a potem coś podobnego

grep -r 'class MyClass' *.php
Peter Mortensen
źródło
Kiedy migruje to do superużytkownika, możesz chcieć powiedzieć coś o tym, czego chciałeś, a co grep -rnie dało.
Jestem zdezorientowany - czy nie odpowiedziałeś tylko sobie? jakie były wyniki tej linii? próbujesz go dalej zoptymalizować? proszę sobie wyobrazić przeczytanie tego pytania jako kogoś innego, ponieważ jest ono mylące i niejasne.
meder omuraliev,
@inne komentarze: Jego wypowiedź grep -r nie daje tego, czego chce, chyba że wszystkie foldery kończą się na .php, co prawdopodobnie nie jest prawdą ...
David Oneill
Nic nie dostałem. Zakładam, że to nie działało, ponieważ wiem, że znajduje je, gdy jestem w folderze, w którym znajduje się plik z tą klasą
Plik znalazłem na szczęście. Podczas wyszukiwania pliku w folderze, w którym znajduje się plik PHP z tą linią, znajduje go (nie ma potrzeby -r). Jeśli włożę CD do katalogu głównego i przeprowadzę wyszukiwanie z rekurencją -r, nic nie zwróci.

Odpowiedzi:

24

Możesz spróbować

grep -r --include=*.php "search string" /path/to/dir
rahul286
źródło
1
Działa świetnie. Wciąż zapominam, ale na szczęście zawsze jest taka odpowiedź, aby mi pomóc. :)
GolezTrol
@GolezTrol Cieszę się, że :-)
rahul286
9

Radziłbym używać czegoś takiego jak ctags zamiast robić to z grep. Jeśli jednak chcesz, możesz zrobić coś takiego

 find <top level dir> -name \*.php | xargs grep "class MyClass"

To oczywiście zakłada, że masz tylko jedną przestrzeń pomiędzy classi myClassktóry nie może być prawda. Łatwo jest jednak zmienić wyrażenie regularne, aby wyszukać dowolną liczbę białych znaków.

Noufal Ibrahim
źródło
4

Jeśli używasz -r, prawdopodobnie chcesz rekurencyjnie przeszukać tylko bieżący katalog :

grep -r 'class MyClass' .

Zwróć uwagę na kropkę na końcu powyższego.

Powiedziałeś, grepże chcesz rekurencyjnie przeszukiwać każdy *.phpplik lub katalog , ale prawdopodobnie nie masz żadnych katalogów, które zakończyłyby się rozszerzeniem .php. Powyższe jest najprostszym możliwym sposobem wyszukiwania, ale obejmuje również pliki innych typów, co jest szczególnie problematyczne, gdy wszędzie masz katalogi .svn. Jeśli nie masz wielu innych typów plików, powyższe jest ogólnie wystarczające i działa dobrze.

Większość inkarnacji grep nie ma sposobu na określenie rozszerzeń plików, które można przeszukiwać, dlatego zwykle używasz find w połączeniu z nim:

find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} \;

-inamemówi niektórym wersjom grep, że chcesz wyszukiwać nazwy plików bez rozróżniania wielkości liter, ale wiele wariantów wyszukiwania innych niż GNU nie obsługuje tego, więc możesz użyć -namezamiast tego.

Powyższa -execopcja ma efekt uboczny wywołania grep dla każdego pliku, co jest dość kosztowne.

Jeszcze inne wersje grep obsługują a, +który każe znaleźć, aby dołączyć argumenty razem, aby zmniejszyć liczbę wywołań pliku wykonywalnego:

find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} + \;

Często zalecanym sposobem ograniczenia wywołań jest użycie xargs, które wystrzelą grep tak mało razy, jak to możliwe, ale tyle razy, ile to konieczne:

find <startDir> -iname \*.php | xargs grep "class[ \t]*MyClass"

xargsjest wystarczająco inteligentny, aby przekazać grep do maksymalnej liczby argumentów obsługiwanych w wierszu poleceń, ale powyższa odmiana nie obsługuje zbyt dobrze niektórych znaków, takich jak spacje. Na przykład, jeśli „plik.php” nazwa pliku grep otrzyma „argument” jako argument i „plik.php” jako argument, więc oba nie zostaną znalezione. Zamiast tego używamy:

find <startDir> -iname \*.php -print0 | xargs -0 grep "class[ \t]*MyClass"

print0oraz -0współpracuj i używaj argumentów, po których następuje znak null, aby argument był całkowicie i jednoznacznie zidentyfikowany.

Jeśli kiedykolwiek masz więcej niż jedną spację classlub tabulator, możesz zezwolić na więcej znaków, zmieniając wyrażenie regularne:class[ \t]*MyClass

Ten post na StackOverflow zawiera inne przykłady i pokazuje, jak wykluczyć niektóre katalogi, takie jak katalogi .svn.

Kaleb Pederson
źródło
Przeszukuje wszystkie pliki. Także pliki, które nie są plikami .php.
GolezTrol
Zaktualizowałem post, aby uwzględnić wiele innych przykładów.
Kaleb Pederson
3

Korzystanie z kiedykolwiek wspaniały ACK ,

ack --php 'class MyClass'
efemeryczny
źródło
1
grep -r 'class MyClass' *.php

przeszuka wszystkie foldery o nazwach kończących się na .php

grep -r 'class MyClass' . | grep .php

wyszuka klasę MyClass we wszystkich plikach we wszystkich podfolderach, a następnie zwróci tylko te, które zawierają .php.

David Oneill
źródło
1

find . -type f -name *.php -print -exec grep \"class MyClass\" {} \; poda zawartość linii, w której się znajduje, oraz ścieżkę do pliku.

prodigitalon
źródło
1

W przypadku, gdy dopasowane pliki mogą mieć dowolne nazwy, należy rozważyć użycie -print0

odnaleźć . -type f -name '* .php' -print0 | xargs -0 grep 'class MyClass'

wudeng
źródło
1
grep -rl 'class MyClass' . --include \*.php

l pokazuje tylko nazwę pliku

r jest cykliczne

. wyszukuje w bieżącym folderze

--include ogranicza rozszerzenie pliku

Pełny
źródło
1

Prawdopodobnie chcesz rozróżniać małe i wielkie litery oraz tolerancję spacji, a grep zakończy działanie, jeśli nie znajdzie żadnych instancji żądanego wzorca pliku w bieżącym katalogu. Musi wiedzieć, od czego zacząć, a żadne dopasowane pliki nie powodują utworzenia ścieżki początkowej.

Jeśli istnieje co najmniej jeden plik o pożądanym rozszerzeniu, możesz użyć egrep -ir. findi xargspokazują swoją moc za pomocą pojedynczych płaskich (ale bardzo dużych) katalogów, w których grep się nie włącza, oraz dodatkowych kwalifikatorów (na przykład, jeśli chcesz wyszukiwać tylko pliki .inc, .php i php3). Ale w moim doświadczeniu traci sporo wygody i szybkości. Dla ludzkich pisemnych deklaracji klasowych dużym problemem będzie spacja. Więc użyj egrep zamiast grep. Również LC_ALL = C dla dodatkowej prędkości. Dla wygody często używam:

LC_ALL=C egrep -irn "class[ ]*myclass([ ]|\n)" * | egrep "\.(inc|php[35]?)"

-i -- case insensitive
-r -- recursive for all file pattern (here *)
-n -- include the line number
LC_ALL=C -- search in ASCII, not in utf8, this is much faster.

[ ]* -- match any number of spaces before the class name
([ ]|\n) -- match a space or newline after the classname

To może nadal pasować do komentarzy, takich jak // class myclass exists in file, ale uważam, że są one stosunkowo małe i można je odfiltrować... | fgrep -v '//'

Możesz również dołączyć bardziej złożone maski plików (na przykład, aby złapać większość plików .inc i .php) we wzorcu pliku egrep, tak jak:

egrep "pattern" *.[ip]*

To (z pierwszymi opcjami) będzie dość szybkie i głównie ograniczone do plików php.

HTH

Beracah
źródło
0

Wiem, że to mówi używanie grep, ale moim osobistym ulubionym jest używanie ack-grep:

ack-grep "class MyClass"

Działa rekurencyjnie, wyświetla nazwę pliku, w którym znajduje wyniki, wraz z numerami wierszy, w których zostały znalezione, i wyróżnia. Aby specjalnie celować w pliki php, możesz uruchomić:

ack-grep --type-set php:ext:php "path"

Pakiet ma wiele opcji; Zdecydowanie poleciłbym to (i przeglądanie powiązanej strony man) do robienia fantazyjnych rzeczy.

jhaagsma
źródło