Я ищу объявление класса на сайте с сотнями файлов PHP. Как я могу сделать это в текущей папке и подпапках, используя grep?
Я проверил cd
в папку, а затем что-то вроде
grep -r 'class MyClass' *.php
Ты можешь попробовать
grep -r --include=*.php "search string" /path/to/dir
Я бы порекомендовал вам использовать что-то вроде ctags, а не с помощью grep. Однако, если вы хотите, вы можете сделать что-то вроде
find <top level dir> -name \*.php | xargs grep "class MyClass"
Это, конечно, предполагает, что у вас есть только один пробел между class
и myClass
который может быть неверным . Однако легко изменить регулярное выражение для поиска любого количества пробелов.
Если вы используете -r
, вы, вероятно, захотите рекурсивно искать только текущий каталог:
grep -r 'class MyClass' .
Обратите внимание на период в конце выше.
Вы сказали, что grep
рекурсивно ищет каждый файл или каталог *.php
, но у вас, скорее всего, нет каталогов, заканчивающихся расширением .php. Выше приведен самый простой способ выполнить поиск, но он также включает файлы других типов, что особенно проблематично, когда у вас есть каталоги .svn везде. Если у вас нет много других типов файлов, вышеприведенного обычно достаточно и работает хорошо.
В большинстве воплощений grep нет способа указать расширения файлов, которые можно искать, поэтому вы обычно используете find вместе с ним:
find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} \;
-iname
сообщает некоторым версиям grep, что вы хотите выполнять поиск имени файла без учета регистра, но многие варианты поиска, отличные от GNU, не поддерживают его, поэтому вы можете использовать вместо него -name
.
Опция -exec
выше, имеет побочный эффект, вызывая grep для каждого файла, что довольно дорого.
Еще в других версиях grep поддерживается знак +
который указывает find добавлять аргументы вместе, чтобы уменьшить количество вызовов исполняемого файла:
find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} + \;
Часто рекомендуемый способ уменьшить количество вызовов - использовать xargs, который будет запускать grep как можно меньше раз, но столько раз, сколько необходимо:
find <startDir> -iname \*.php | xargs grep "class[ \t]*MyClass"
xargs
достаточно умен, чтобы передать grep до максимального числа аргументов, поддерживаемых в командной строке, но вышеописанный вариант не очень хорошо обрабатывает некоторые символы, например пробелы. Например, если в файле 'file.php' имя файла grep получит аргумент 'the', а в качестве аргумента 'file.php', оба файла не будут найдены. Вместо этого мы используем:
find <startDir> -iname \*.php -print0 | xargs -0 grep "class[ \t]*MyClass"
print0
и -0
работают вместе и используют аргументы, за которыми следует нулевой символ, чтобы аргумент был полностью и однозначно идентифицирован.
Если у вас есть более одного пробела после class
или табуляции, вы можете захотеть добавить больше символов, изменив регулярное выражение: class[ \t]*MyClass
Этот пост в StackOverflow содержит другие примеры и демонстрирует, как исключить определенные каталоги, например, каталоги .svn.
Используя когда-либо замечательное подтверждение,
ack --php 'class MyClass'
grep -r 'class MyClass' *.php
будет искать во всех папках с именами, заканчивающимися на .php
grep -r 'class MyClass' . | grep .php
будет искать класс MyClass во всех файлах во всех подпапках, а затем будет возвращать только те, которые имеют .php в них.
find . -type f -name *.php -print -exec grep \"class MyClass\" {} \;
выдаст содержимое строки, в которой он найден, а также путь к файлу.
grep -rl 'class MyClass' . --include \*.php
л показывает только имя файла
г
, поиск в текущей папке
--include ограничивает расширение файла
В случае, если совпадающие файлы могут иметь произвольные имена, вы должны рассмотреть возможность использования -print0
находить . -type f -name '* .php' -print0 | xargs -0 grep 'class MyClass'
Вероятно, вам нужна нечувствительность к регистру и допуски на пробелы, и grep прекратит работу, если не найдет ни одного экземпляра желаемого шаблона файла в текущем каталоге. Он должен знать, с чего начать, и никакие файлы не дают начального пути.
Если существует хотя бы один файл с желаемым расширением, вы можете использовать egrep -ir. find
и xargs
показывают свою мощь с помощью единственных плоских (но очень больших) каталогов, в которых сбой grep, и дополнительных квалификаторов (например, если вы хотите искать только файлы .inc, .php и php3). Но он теряет немного удобства и скорости в моем опыте. Для объявлений, написанных человеком, большой проблемой будет пробел. Так что используйте egrep вместо grep. Также LC_ALL = C для дополнительной скорости. Для удобства я часто использую:
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
Это все еще может соответствовать комментариям, например, // class myclass exists in file
, но я считаю, что они относительно небольшие, и их можно отфильтровать с помощью ... | fgrep -v '//'
Вы также можете включить более сложные маски файлов (например, чтобы перехватить большинство файлов .inc и .php) в шаблон файла egrep следующим образом:
egrep "pattern" *.[ip]*
Это (с первыми опциями) будет довольно быстрым и в основном ограничивается php-файлами.
НТН
Я знаю, что это говорит об использовании grep
, но мой личный фаворит - использовать ack-grep
:
ack-grep "class MyClass"
Это выполняется рекурсивно, перечисляет имя файла, в котором он находит результаты, с номерами строк, где они находятся, и выделяет. Чтобы специально настроить php-файлы, вы можете запустить:
ack-grep --type-set php:ext:php "path"
Пакет имеет множество вариантов; Я определенно рекомендую его (и просматриваю связанную с ним справочную страницу) для выполнения модных вещей.