Grep мультилинейный рисунок


13

Как мне найти фразу в нескольких строках? Например, давайте напишем фразу «мой ледяной чай», тогда она может быть обернута в текстовые файлы:

as js skdfh dfh djh sf my
ice tea.

grep не будет совпадать, так как между ними есть новая строка. Как мне соответствовать этим? Другой многострочный шаблон будетpattern1_\n_pattern2

Я знаю, что самый простой способ, которым я делаю ATM, это просто grep для одной части, например, лед с флагом -A2 -B2 и затем в этом выходе, например, чай. Но это очень утомительно. Поэтому я заинтересован в том, как бы вы решили это.


1
возможный межсайтовый дубликат: stackoverflow.com/questions/152708/…
Ciro Santilli 事件 改造 中心 法轮功 六四 事件

Ответы:


16

Вы можете установить pcregrep(доступно в большинстве репозиториев дистрибутивов) - это grep с использованием библиотеки pcre , которая выполняет "Perl-совместимые регулярные выражения". Он имеет параметр командной строки, -Mкоторый позволяет выполнять многострочный поиск - со страницы руководства :

«Вывод для любого совпадения может состоять из нескольких строк».

Так что вы могли бы сделать

pcregrep -M 'my\s+ice\s+tea' filename

Это \sпробел, который будет соответствовать \nи \rв многострочном режиме, в дополнение к обычным пробельным символам. Вы также можете напрямую сопоставить символ новой строки, чтобы вы могли сделать

pcregrep -M 'pattern1_\n_pattern2' filename

+1 приятно. никогда не слышал об этом, но попробовал, и это работает как шарм!
DaveParillo

Не grep -Eделает PCR шаблонов?
Дейнит

3
@Daenyth Grep -E в основном просто означаете , что вы можете использовать ?, +, {, |, (, и )как их обычный регулярное выражение смысла без необходимости иметь \ впереди, как вы делаете , если вы используете стандартный Grep. Так grep 'hello\s\+world' fileэквивалентно grep -E 'hello\s+world' file. Это не делает PCRE. Существует grep -Pдля регулярных выражений Perl, но это экспериментальный (согласно man-странице), и я думаю, что это немного отличается от pcregrep ...
Хэмиш Даунер

1
Да, я думал о том, -Pкогда сказал -E, но я не осознавал, что все было иначе.
Дейнит

3

Я бы , вероятно , сделать поиск , используя vim«s :vimgrepкоманды. Это работает примерно так же, как и для grepvim RE и путей.

По сути, вы запускаете что-то вроде :vimgrep 'pattern1\npattern2' path/**рекурсивного поиска, затем :copenнабираете, чтобы вызвать меньшее окно, содержащее список совпадений.

vimRE могут делать в основном все, что могут PCRE, но они развивались отдельно от линии регулярных выражений perl, поэтому большинство продвинутых вещей работает по-другому. Их базовая функциональность больше похожа на базовые RE, но у них есть некоторые изящные дополнения, которые PCRE не предлагают.

Я не уверен, можно :vimgrepли выкладывать данные, как это grepделает; Я только пытался использовать его для навигации внутри vim.

:help vimgrepизнутри vimдля получения дополнительной информации; :help pattern.txtдля получения информации о vimРЗ; Для получения дополнительной информации о путях см :help wildcards.


Будьте осторожны - это не совсем переносимо, так как на разных платформах будет вести себя по-разному
Daenyth

1
@Daenyth: ты имеешь в виду под влиянием разных .vimrc? Он должен быть более переносимым, чем в grepотношении операционной системы: vimне имеет «POSIX-аромата» и работает более или менее идентично даже под Windows. .................................................. ............................ Можно добавить квалификаторы, чтобы гарантировать, что, например, правильное количество "магии" используется в RE, хотя насколько я понимаю, существует строгое неписаное правило, чтобы этот вариант оставался в покое.
интуитивно

Я не использовал его сам, но очевидно, что он использует другой бэкэнд в Windows ( find.exeвместо grep). В течение последних нескольких недель был еще один вопрос, который имел эту проблему.
Дейнит

1
@Daenyth: ты думаешь :vimgrepили :grep? От :help grep: «Преимущество внутреннего grep [то есть :vimgrep] в том, что он работает во всех системах и использует мощные шаблоны поиска Vim».
интуитивно

1
Ах, это должно быть так. Я запутался в двух.
Дейнит

2

Grep работает только по одной строке за раз, но вы можете использовать awk для печати строк, соответствующих ряду шаблонов:

cat file | awk '/foo/,/bar/'

это будет соответствовать чему угодно, а не только переводу строк между двумя шаблонами


0

Чтобы получить максимальную отдачу от Unix, вам нужно использовать преимущества труб. Вы можете сделать это обычным способом, grepиспользуя трубы (нет необходимости в тройнике):

$ grep -A1 "pattern1" file.txt |  grep "pattern2"

Что я не считаю утомительным.


Я думаю, что это подвержено ошибкам, так как между pattern1 и pattern2 может существовать pattern3, который может не соответствовать тому, что вы ищете. Таким образом, вы должны контролировать каждый удар вручную.
математическое
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.