Кажется, я неправильно использую grep
/ egrep
.
Я пытался найти строки в несколько строк и не смог найти совпадение, хотя я знаю, что то, что я ищу, должно совпадать. Первоначально я думал, что мои регулярные выражения были неправильными, но в конце концов я прочитал, что эти инструменты работают в каждой строке (также мои регулярные выражения были настолько тривиальными, что это не могло быть проблемой).
Итак, какой инструмент можно использовать для поиска шаблонов по нескольким строкам?
grep
. Они тесно связаны, но не дураки, ИМО."grep"
предлагая глагол "grep", а в верхних ответах, включая принятые, не используйте grep.Ответы:
Вот
sed
тот, который даст вамgrep
подобное поведение в нескольких строках:Как это работает
-n
подавляет поведение по умолчанию при печати каждой строки/foo/{}
инструктирует его, чтобы соответствоватьfoo
и делать то, что происходит внутри волнистых линий к соответствующим линиям. Заменитьfoo
начальной частью шаблона.:start
является меткой ветвления, которая помогает нам продолжать цикл, пока мы не найдем конец нашему регулярному выражению./bar/!{}
выполнит то, что в волнистых линиях, линиям, которые не совпадаютbar
. Заменитьbar
на конечную часть рисунка.N
добавляет следующую строку в активный буфер (sed
вызывает это пространство шаблона)b start
будет безоговорочно переходить кstart
метке, которую мы создали ранее, чтобы продолжать добавлять следующую строку, пока пространство шаблона не содержитbar
./your_regex/p
печатает пространство шаблона, если оно совпадаетyour_regex
. Вы должны заменитьyour_regex
все выражение, которое вы хотите найти в нескольких строках.источник
sed: 1: "/foo/{:start /bar/!{N;b ...": unexpected EOF (pending }'s)
sed: unterminated {
ошибкиsed
реализациями. Я попытался следовать рекомендациям в этом ответе, чтобы сделать приведенный выше сценарий совместимым со стандартом, но он сказал мне, что «start» - это неопределенная метка. Поэтому я не уверен, что это можно сделать стандартным образом. Если вам это удастся, пожалуйста, не стесняйтесь редактировать мой ответ.Обычно я использую инструмент,
pcregrep
который можно установить в большинстве вариантов linux, используяyum
илиapt
.Например,
Предположим, если у вас есть файл
testfile
с именем содержимогоВы можете запустить следующую команду:
сделать сопоставление с образцом через несколько строк.
Более того, вы можете сделать то же самое с
sed
.источник
Вот более простой подход с использованием Perl:
или (с JosephR взял
sed
маршрут , я бессовестно украсть его предложение )объяснение
$f=join("",<>);
: это читает весь файл и сохраняет его содержимое (новые строки и все) в переменную$f
. Затем мы пытаемся найти совпадениеfoo\nbar.*\n
и вывести его, если оно совпадает (специальная переменная$&
содержит последнее найденное совпадение).///m
Необходимо , чтобы сделать регулярное выражение матч через переводы строк.-0
Устанавливает входной разделитель записей. Установка этого параметра00
активирует «режим абзаца», где Perl будет использовать последовательные символы новой строки (\n\n
) в качестве разделителя записей. В тех случаях, когда нет последовательных символов новой строки, весь файл читается (удаляется) сразу.Предупреждение:
Как не сделать это для больших файлов, она будет загружать весь файл в память , и это может быть проблемой.
источник
Один из способов сделать это с Perl. например, вот содержимое файла с именем
foo
:Теперь, вот некоторые Perl, которые будут сопоставляться с любой строкой, начинающейся с foo, за которой следует любая строка, начинающаяся с bar:
Perl, сломанный:
while(<>){$all .= $_}
Это загружает весь стандартный ввод в переменную$all
while($all =~
В то время как переменнаяall
имеет регулярное выражение .../^(foo[^\n]*\nbar[^\n]*\n)/m
Регулярное выражение: foo в начале строки, за которым следует любое количество символов, не являющихся символом новой строки, за которыми следует символ новой строки, сразу за ним следует «bar», а остальная часть строки - с символом bar./m
в конце регулярного выражения означает "совпадать через несколько строк"print $1
Выведите часть регулярного выражения, которая была в скобках (в данном случае, все регулярное выражение)s/^(foo[^\n]*\nbar[^\n]*\n)//m
Удалите первое совпадение для регулярного выражения, чтобы мы могли сопоставить несколько случаев регулярного выражения в рассматриваемом файле.И вывод:
источник
perl -n0777E 'say $& while /^foo.*\nbar.*\n/mg' foo
Альтернативный sift grep поддерживает многострочное сопоставление (отказ от ответственности: я автор).
Предположим,
testfile
содержит:sift -m '<description>.*?</description>'
(показать строки, содержащие описание)Результат:
sift -m '<description>(.*?)</description>' --replace 'description="$1"' --no-filename
(извлечь и переформатировать описание)Результат:
источник
Просто нормальный grep, который поддерживает
Perl-regexp
параметрP
, сделает эту работу.(?s)
называется модификатором DOTALL, который ставит точку в регулярном выражении, чтобы соответствовать не только символам, но и разрывам строк.источник
-P
опциюЯ решил это для меня, используя опцию grep и -A с другим grep.
Опция -A 1 печатает 1 строку после найденной строки. Конечно, это зависит от вашего файла и словосочетания. Но для меня это было самое быстрое и надежное решение.
источник
Предположим, у нас есть файл test.txt, содержащий:
Следующий код может быть использован:
Для следующего вывода:
источник
Если мы хотим получить текст между двумя шаблонами, исключая самих себя.
Предположим, у нас есть файл test.txt, содержащий:
Следующий код может быть использован:
Для следующего вывода:
Как это работает, давайте сделаем это шаг за шагом
/foo/{
срабатывает, когда строка содержит "foo"n
замените пространство шаблона следующей строкой, т.е. словом «здесь»b gotoloop
ветка с лейблом "готолуп":gotoloop
определяет метку "gotoloop"/bar/!{
если шаблон не содержит "бар"h
замените пространство удержания на шаблон, так что «здесь» сохраняется в пространстве удержанияb loop
ветка с ярлыком "петля":loop
определяет метку "петля"N
добавляет шаблон в пространство удержания.Теперь трюм содержит:
"здесь"
"это"
:gotoloop
Теперь мы находимся на шаге 4 и выполняем цикл, пока строка не будет содержать «bar»/bar/
цикл завершен, "бар" был найден, это образец пространстваg
Пространство шаблона заменяется пространством удержания, которое содержит все строки между «foo» и «bar», которые были сохранены во время основного циклаp
скопировать пространство шаблона в стандартный выводВыполнено !
Sed Multiline Loop
источник