Regex (grep) для многострочного поиска
Возможный дубликат:
Как искать многострочный шаблон в файле? Использовать pcregrep
Я запустил grep
, чтобы найти файл *.sql, который имеет слово select
, за которым следует слово customerName
, за которым следует слово from
. Этот оператор select может охватывать множество строк и может содержать табуляции и новые строки.
Я пробовал несколько вариантов:
$ grep -liIr --include="*.sql" --exclude-dir="\.svn*" --regexp="select[a-zA-Z0-
9+\n\r]*customerName[a-zA-Z0-9+\n\r]*from"
Это, однако, просто работает вечно. Может ли кто-нибудь помочь мне с правильным синтаксисом, пожалуйста?
Ответы
Ответ 1
Без необходимости устанавливать вариант grep pcregrep, вы можете выполнять многострочный поиск с помощью grep.
$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^\1}" *.c
Объяснение:
-P
активировать perl-regexp для grep (мощное расширение регулярных выражений)
-z
подавляет -z
новой строки в конце строки, заменяя его нулевым символом. То есть grep знает, где находится конец строки, но видит входные данные как одну большую строку.
-o
только для печати. Поскольку мы используем -z
, весь файл похож на одну большую строку, поэтому при совпадении будет напечатан весь файл; таким образом, это не будет делать это.
В регулярном выражении:
(?s)
активировать PCRE_DOTALL
, а это значит .
находит любой символ или перевод строки
\N
найти что-нибудь кроме новой строки, даже с активированным PCRE_DOTALL
.*?
найти .
в несжатом режиме, то есть останавливается как можно скорее.
^
найти начало строки
\1
обратная ссылка на первую группу (\s*
) Это попытка найти тот же отступ метода
Как вы можете себе представить, этот поиск печатает метод main в исходном файле C (*.c
).
Ответ 2
Я не очень хорош в grep. Но ваша проблема может быть решена с помощью команды AWK.
Просто посмотрите
awk '/select/,/from/' *.sql
Вышеприведенный код будет результатом первого появления select
до первой последовательности from
. Теперь вам нужно проверить, имеют ли возвращенные операторы customername
или нет. Для этого вы можете передать результат. И может снова использовать awk или grep.
Ответ 3
Ваша основная проблема заключается в том, что 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
}
}
Это должно быть завернуто в sub, который затем вызывается методами File:: Find.