Как мне найти строку в файле PHP, используя `grep`?

11

Я ищу объявление класса на сайте с сотнями PHP-файлов. Как я могу сделать это в текущей папке и подпапках, используя grep ?

Я проверил cdIN в папку, а затем что-то вроде

grep -r 'class MyClass' *.php
Питер Мортенсен
источник
Когда это переходит на суперпользователя, вы можете захотеть сказать что-то о том, что вы хотели, что grep -rне дало вам.
Я в замешательстве - ты сам не ответил? каковы были результаты этой линии? Вы пытаетесь оптимизировать его? пожалуйста, представьте, что читаете этот вопрос как кто-то другой, потому что он запутанный и неясный.
медер омуралиев
@ другие комментарии: Его утверждение grep -r не дает того, что он хочет, если только все папки не заканчиваются на .php, что, вероятно, не так ...
David Oneill
Я ничего не получил вообще. Я предполагаю, что это не сработало, потому что я знаю, что находит его, когда я нахожусь в папке, где находится файл с этим классом
Я нашел файл по счастливой случайности. При поиске файла в папке, в которой находится PHP-файл с этой строкой, он находит его (нет необходимости в -r). Если я отправляю CD в корень и выполняю поиск с помощью рекурсии -r, он ничего не возвращает.

Ответы:

24

Можешь попробовать

grep -r --include=*.php "search string" /path/to/dir
rahul286
источник
1
Прекрасно работает. Я продолжаю забывать, но, к счастью, всегда есть этот ответ, чтобы помочь мне. :)
GolezTrol
@GolezTrol Рад знать, что :-)
rahul286
9

Я бы порекомендовал вам использовать что-то вроде ctags, а не с помощью grep. Однако, если вы хотите, вы можете сделать что-то вроде

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

Это, конечно, предполагает, что между вами есть только один пробел, classи myClassэто может быть неверно. Однако легко изменить регулярное выражение для поиска любого количества пробелов.

Нуфал Ибрагим
источник
4

Если вы используете -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 поддерживают a, +который сообщает 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.

Калеб Педерсон
источник
Это ищет все файлы. Также файлы, которые не являются .php файлами.
GolezTrol
Я обновил пост, чтобы включить много других примеров.
Калеб Педерсон
1
grep -r 'class MyClass' *.php

будет искать во всех папках с именами, заканчивающимися на .php

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

будет искать класс MyClass во всех файлах во всех подпапках, а затем будет возвращать только те, которые имеют .php в них.

Дэвид Онеилл
источник
1

find . -type f -name *.php -print -exec grep \"class MyClass\" {} \; даст вам содержимое строки, в которой он найден, а также путь к файлу.

prodigitalson
источник
1

В случае, если совпадающие файлы могут иметь произвольные имена, вы должны рассмотреть возможность использования -print0

находить . -type f -name '* .php' -print0 | xargs -0 grep 'class MyClass'

wudeng
источник
1
grep -rl 'class MyClass' . --include \*.php

л показывает только имя файла

г

, поиск в текущей папке

--include ограничивает расширение файла

Полный
источник
1

Возможно, вам нужна нечувствительность к регистру и допуск пробелов, и 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-файлами.

НТН

благословения
источник
0

Я знаю, что это говорит об использовании grep, но мой личный фаворит - использовать ack-grep:

ack-grep "class MyClass"

Это выполняется рекурсивно, перечисляет имя файла, в котором он находит результаты, с номерами строк, где они находятся, и выделяет. Чтобы специально настроить php-файлы, вы можете запустить:

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

Пакет имеет множество вариантов; Я определенно рекомендую его (и просматриваю связанную с ним справочную страницу) для выполнения модных вещей.

jhaagsma
источник