Regex (grep) для многострочного поиска [дубликат]

Возможные Дубликаты:
как я могу искать многострочный шаблон в файл ? Использовать pcregrep

Я grep найти *.файл sql, который имеет слово select после слова customerName после слова from. Эта инструкция select может охватывать множество строк и содержать вкладки и новые строки.

Я пробовал несколько вариантов следующего:

$ grep -liIr --include="*.sql" --exclude-dir=".svn*" --regexp="select[a-zA-Z0-
9+nr]*customerName[a-zA-Z0-9+nr]*from"

этот, однако, просто бежит вечно. Кто-нибудь может помочь мне с правильным синтаксисом, пожалуйста?

3 ответов


без необходимости установки grep вариант pcregrep, вы можете сделать многострочный поиск с grep.

$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^}" *.c

объяснение:

-P активировать perl-regexp для grep (мощное расширение регулярных расширений)

-z подавления новой строки в конце строки, subtituting это для нуль-символа. То есть grep знает, где конец строки, но видит вход как одну большую строку.

-o печать только соответствия. Потому что мы используем -z, весь файл похож на одну большую строку, поэтому, если есть совпадение, весь файл будет напечатан; таким образом, он этого не сделает.

в регулярное выражение:

(?s) активировать PCRE_DOTALL, что означает . находит любой символ или строку

\N найти что-нибудь, кроме newline, даже с PCRE_DOTALL активирован

.*? найти . в режиме из жадного в нежадный, то есть как можно быстрее останавливается.

^ найти начало линия

backreference к первой группе (\s*) это попытка найти тот же отступ метода

как вы можете себе представить, этот поиск выводит основной метод в C (*.c файл) источник.



ваша основная проблема в том, что 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.