Требуется регулярное выражение (grep) для многострочного поиска
Возможный дубликат:
Как мне найти многострочный шаблон в файле? Используйте pcregrep
Я бегу grep
найти любой файл *.sql со словом select
с последующим словом customerName
с последующим словом from
, Этот оператор выбора может занимать много строк и может содержать вкладки и новые строки.
Я пробовал несколько вариантов на следующее:
$ grep -liIr --include="*.sql" --exclude-dir="\.svn*" --regexp="select[a-zA-Z0-
9+\n\r]*customerName[a-zA-Z0-9+\n\r]*from"
Это, однако, работает вечно. Может кто-нибудь помочь мне с правильным синтаксисом, пожалуйста?
3 ответа
Без необходимости устанавливать вариант grep pcregrep, вы можете выполнять многострочный поиск с помощью grep.
$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^\1}" *.c
Объяснение:
-P
активировать perl-regexp для grep (мощное расширение регулярных расширений)
-z
подавить символ новой строки в конце строки, подставив его для нулевого символа. То есть grep знает, где находится конец строки, но видит входные данные как одну большую строку.
-o
печатать только соответствующие. Потому что мы используем -z
весь файл похож на одну большую строку, поэтому при совпадении будет напечатан весь файл; таким образом, это не будет делать это.
В регулярном выражении:
(?s)
активировать PCRE_DOTALL
, Который означает, что .
находит любой символ или перевод строки
\N
найти что-нибудь кроме новой строки, даже с PCRE_DOTALL
активированный
.*?
находить .
в несжатом режиме, то есть останавливается как можно скорее.
^
найти начало строки
\1
обратная ссылка на первую группу (\s*
) Это попытка найти тот же отступ метода
Как вы можете себе представить, этот поиск печатает основной метод в C (*.c
) исходный файл.
Я не очень хорош в grep. Но ваша проблема может быть решена с помощью команды AWK. Просто посмотри
awk '/select/,/from/' *.sql
Приведенный выше код будет результатом первого появления select
до первой последовательности from
, Теперь вам нужно проверить, имеют ли возвращаемые операторы customername
или нет. Для этого вы можете передать результат. И можете использовать awk или grep снова.
Ваша основная проблема в том, что grep
работает по одной строке за раз - поэтому он не может найти оператор SELECT, разбросанный по строкам.
Ваша вторая проблема заключается в том, что используемое вами регулярное выражение не связано со сложностью того, что может появиться между SELECT и FROM - в частности, оно пропускает запятые, точки остановки (точки) и пробелы, а также кавычки и все, что может быть внутри строка в кавычках.
Скорее всего, я бы выбрал решение на основе Perl, в котором Perl считывал "абзацы" за раз и применял к этому регулярное выражение. Недостатком является то, что приходится иметь дело с рекурсивным поиском - для этого есть, конечно, модули, в том числе основной модуль File:: Find.
В общих чертах, для одного файла:
$/ = "\n\n"; # Paragraphs
while (<>)
{
if ($_ =~ m/SELECT.*customerName.*FROM/mi)
{
printf file name
go to next file
}
}
Это должно быть заключено в подпрограмму, которая затем вызывается методами File::Find.