Як я можу шукати багаторядковий візерунок у файлі?


128

Мені потрібно було знайти всі файли, які містили певний рядковий шаблон. Перше рішення, яке вам спадає на думку, - це використовувати find pipe, з xargs grep :

find . -iname '*.py' | xargs grep -e 'YOUR_PATTERN'

Але якщо мені потрібно знайти візерунки, що охоплюють більше одного рядка, я застряг, оскільки ванільний греп не може знайти багатолінійні візерунки.



2
Цей старший, тому я б сказав, що це не дублікат :)
rogerdpack

@rogerdpack Під час позначення питань як дублікатів вік питання викликає третє значення, залежно від кількості та якості відповідей та якості запитання.
tripleee

Відповіді:


98

Тож я виявив pcregrep, який розшифровується як Perl Compatible Regular Express GREP .

Наприклад, вам потрібно знайти файли, де за змінною ' _name ' негайно слідує змінна ' _description ':

find . -iname '*.py' | xargs pcregrep -M '_name.*\n.*_description'

Порада: вам потрібно включити символ розриву рядка до вашого шаблону. Залежно від вашої платформи, це може бути "\ n", \ r ',' \ r \ n ', ...


7
Як згадує Халка нижче, "ви також можете переконати підстановку точок у відповідність новим рядкам, якщо ви додасте (? S) до свого регулярного виразу". Потім використовуйте греп з пергель, додаючи -П. знайти. -exec grep -nHP '(? s) SELECT. {1,60} ВІД. {1,20} ім'я таблиці_'' {}' \;
Джим

8
pcregrepдоступний на mac зbrew install pcre
Джаред Бек

1
Ще краще: використовувати -Hякий друкує ім'я файлу перед кожним матчем: pcregrep -HM.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

97

Чому б вам не піти на лихо :

awk '/Start pattern/,/End pattern/' filename

2
Це набагато простіше зрозуміти та використовувати, awkщо постачається з більшістю * nix систем.
Алі Карбассі

24
приємно! чи є спосіб зробити цей матч не жадібним?
marcin

3
Як би ви друкували ім'я файлу лише тоді, коли є збіг?
bibstha

2
Ви можете показати номери рядків збігів із awk '/Start pattern/,/End pattern/ {printf NR " "; print}' filename. Ви можете зробити це покращала, даючи номера рядків фіксованої ширини: awk '/Start pattern/,/End pattern/ {printf "%-4s ", NR; print}' filename.
Роберт

Здається, це добре працює на одному файлі, однак, що робити, якщо я хотів би шукати в декількох файлах?
Jinstrong

84

Ось приклад використання GNUgrep :

grep -Pzo '_name.*\n.*_description'

-z/ --null-dataТрактуйте вхідні та вихідні дані як послідовності рядків.

Дивіться також тут


1
Я думаю, що це лише один символ нового рядка.
Хмара

1
Мені не вдалося використати grep для багатолінійного пошуку, не використовуючи прапори, -zщоб він не розділив пошук на одну лінію та -oдрукувати лише сумісну частину.
bbaja42

Я виявив, що - я змусив його нічого не друкувати, але - працював над тим, щоб отримати список файлів (моя команда була grep -rzl pattern *, -rzo не працював)
Benubird

5
Я рекомендую '' grep -Pazo '' замість '' -Pzo '' для файлів, що не містять ASCII. Це краще, тому що перемикач -z на файли, що не належать до ASCII, може викликати поведінку grep "бінарних даних", що змінює повернені значення. Перемикач '' -a | --tekst '' запобігає цьому.
rloth

Не працює на Mac із встановленим gitbrew reinstall --with-pcre git
Quanlong

21

grep -Pтакож використовує libpcre, але набагато ширше встановлюється. Щоб знайти повний titleрозділ html-документа, навіть якщо він охоплює кілька рядків, ви можете скористатися цим:

grep -P '(?s)<title>.*</title>' example.html

Оскільки проект PCRE реалізовується до стандарту perl, використовуйте документацію perl для довідки:


Хм, спробував це зараз і, схоже, не спрацювало ... gist.github.com/rdp/0286d91624930bd11d0169d6a6337c33
rogerdpack

Я не знав , Grep мав таку можливість. Можливо, через це: Це дуже експериментально, а греп -P може попередити про бездоганну функцію. ; це під CentOS 7. У розділі Fedora 29: Це експериментально, а grep -P може попередити про бездоганні функції . Звичайно, у BSD grep його взагалі немає. Було б добре, якби це було не так експериментально, але приємно нагадати про це - мало, хоча я, швидше за все, ним користуюся.
Прифтан

17

Ось більш корисний приклад:

pcregrep -Mi "<title>(.*\n){0,5}</title>" afile.html

Він шукає тег заголовка у HTML-файлі, навіть якщо він охоплює до 5 рядків.

Ось приклад необмежених рядків:

pcregrep -Mi "(?s)<title>.*</title>" example.html 

4
спасибі за це. Я застряг, не розуміючи, що макіяж не відповідає новому символу.
мат

7
@matt: ви також можете переконати підстановку підкреслених точок, щоб вони відповідали новим рядкам, якщо ви додасте (?s)до свого звичайного виразу, як-от так:"(?s)<html>.*</html>"
lubomir.brindza

@matt Звичайно, ви можете перевірити наявність $(в кінці шаблону), щоб позначити, що це кінець рядка, хоча це не те саме, що допомогти вам знайти кілька моделей ліній. Дивіться також glob(7). Ви також можете знайти цей сайт інтерес: regular-expressions.info
Pryftan


4

Ви можете використовувати альтернативну просіювання grep тут (відмова: Я - автор).

Він підтримує багаторівневу відповідність та обмежує пошук певних типів файлів поза вікном:

просіти -m --files '* .py' 'YOUR_PATTERN'

(пошук у всіх * .py файлах за вказаною багаторядковою схемою регулярного виразка)

Він доступний для всіх основних операційних систем. Погляньте на сторінку зразків, щоб побачити, як з його допомогою можна витягувати багаторядкові значення з XML-файлу.


3

Ця відповідь може бути корисною:

Для багаторядкового пошуку потрібен Regex (grep)

Щоб знайти рекурсивно, ви можете використовувати прапори -R (рекурсивний) та --include (шаблон GLOB). Побачити:

Використовуйте grep --exclude / - включайте синтаксис, щоб не проглядати певні файли


@ Ɖiamond ǤeezeƦ відзначити , що редагування поста в Lqp ( stackoverflow.com/review/low-quality-posts/19341146 ) Анулює огляд, так просто змінити , якщо ви впевнені , що поштові необхідно підтримувати.
fedorqui 'ТАК перестаньте шкодити'

2

@Marcin: awk приклад не жадібний:

awk '{if ($0 ~ /Start pattern/) {triggered=1;}if (triggered) {print; if ($0 ~ /End pattern/) { exit;}}}' filename


1

Використання параметрів ex/ vieditor та globstar (синтаксис подібний до awkта sed):

ex +"/string1/,/string3/p" -R -scq! file.txt

де aaaваша відправна точка і bbbваш кінцевий текст.

Для рекурсивного пошуку спробуйте:

ex +"/aaa/,/bbb/p" -scq! **/*.py

Примітка. Щоб увімкнути **синтаксис, запустіть shopt -s globstar(Bash 4 або zsh).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.