Соответствующая многострочная строка в командной строке: возвращает определенную строку, если шаблон соответствует, иначе возвращает пустую строку
Вывод команды, которую я имею, принимает следующую форму, когда это "успех":
/ > -------
ABC123
/ >
Впрочем, эта команда может выдать что-то вроде этого ("сбой"):
/ > -------
ABC123
-------
DEF456
-------
Hello (world!)
-------
(any old string, really)
/ >
Или это (еще один "провал"):
/ > / >
Для первого примера я хотел бы выпустить:
ABC123
Для других двух примеров я хотел бы выдать пустую строку.
Я попробовал это, который отлично работал для третьего примера:
mycmd | pcregrep -M '(?:/\s>\s{2}-{7}\n)[^\n]*(?!\n.*\n)'
Но для первых двух примеров он испустил:
/ > -------
ABC123
Я в недоумении, что делать. Мое регулярное выражение выше было попыткой соответствовать ведущему / > -------
но не перехватывать его, затем сопоставлять следующую строку, только если за ней не следовала другая строка, заканчивающаяся символом новой строки. Я в порядке, используя что-то, кроме pcregrep
чтобы решить эту проблему, но я не могу выразить это с awk
или же sed
, Я бы использовал Python, но он слишком медленный для моих нужд. Любая помощь?
3 ответа
Я думал, что следующее сработает, но я не мог заставить работать выражение для просмотра, если оно содержало перевод строки.
mycmd | pcregrep -M '(?<=^/ > -{7}\n).*\n(?=/ > $)'
Но следующие два этапа работали для меня:
mycmd | pcregrep -M '^/ > -{7}\n.*\n/ > $' | pcregrep -v '^/ >'
Обновление в ответ на ответ ОП
Мне нравится побег \K:-)
Я предполагаю, что вы не хотите соответствовать следующей ситуации
/ > -------
/ > perhaps text here
/ >
Мне удалось заставить работать отрицательный взгляд вперед, когда он содержит \ n, даже если он встроен в положительный взгляд вперед.
Вот более простое регулярное выражение с \K
это ближе к тому, что вы хотите. Запрещает любой контент после / >
, но он все еще позволяет линии до / > -------
,
mycmd | pcregrep -Mo '^/ > -{7}\n\K(?!/ >).+(?=\n/ > $(?!\n[\s\S]))'
Если захваченная строка должна быть разрешена для начала с / >
тогда проще:
mycmd | pcregrep -Mo '^/ > -{7}\n\K.+(?=\n/ > $(?!\n[\s\S]))'
Окончательное обновление
Вот один вкладыш sed, который, я считаю, дает точный результат, запрещая любые дополнительные строки до или после. Тем не менее, он позволяет захватить строку, которая начинается с / >
,
mycmd | sed -n '1{/^\/ > -\{7\}$/{n;/./{h;n;/^\/ > $/{${x;p}}}}}'
И вот еще одно решение для sed
mycmd | sed -n '1{h;n;H;x;N;${/^\/ > -\{7\}\n..*\n\/ > $/{x;p}}}'
Я действительно добился успеха (после большого скрежета зубов) со следующими pcregrep
команда:
pcregrep -Mo '^/ > {2}-{7}[\n\r]\K[^\n\r]+(?=[\n\r]/ > $)'
Без -o
Отметить, что он включил первую строку (несмотря на использование \K
). -o
марки pcregrep
испускать только те линии, которые соответствуют шаблону. Как выясняется, негативные упреждения, похоже, не работают в многострочном режиме при попытке сопоставления с новыми строками. Также в многострочном режиме \s
будет соответствовать переводу строк, поэтому я перестал его использовать.
Я хочу отметить, что ни это решение, ни решение dbenham - это не то, что я хотел. Я надеялся проверить, что после второй строки не было никаких других строк, кроме последней (т. Е. Не содержащей другой новой строки). Эти решения предполагают немного больше о том, как заканчивается вывод, но это нужно сделать.
Вы также можете использовать awk:
BEGIN {
first_line = "";
second_line = "";
third_line = "";
ctr = 0;
}
{
if (ctr == 0 ){
first_line = $0;
} else if (ctr == 1) {
second_line = $0;
} else if (ctr == 2 ) {
third_line = $0;
}
ctr++;
}
END {
if( first_line ~ /\/ > -------/){
if( third_line ~ /\/ >/){
print second_line;
}
}
}
Выход:
$ echo "/ > -------\nABC12\n ---\n/ >\n" | awk -f test.awk
$ echo "/ > -------\nABC12\n/ >\n" | awk -f test.awk
ABC12
$
Я уверен, что специалист по awk съежился бы, но это было быстро и сделало свою работу.