1

Я ищу одну команду лайнера (в лучшем случае), которая может найти, если конкретная строка / строка представлена между двумя другими строками. Я ищу его, и я нашел только запятую, чтобы получить содержимое между двумя строками, но как я могу проверить, присутствует ли что-то или нет ..

.....
 1 a 2 b 3
 4
   5
.....
 1 c 2 d 3
 4
   5
.....
 1 e 2 f 3
   5
.....

Я нашел это:

sed -n '/^ 1 .* 2 .* 3$/,/^ 5$/p'

результат с этой командой обрезал нежелательные строки, подходящие для запуска (обрезал строки "...."), но все еще не знает, как проверить, присутствует ли "4" между:

 1 a 2 b 3
 4
   5
 1 c 2 d 3
 4
   5
 1 e 2 f 3
   5

Вывод должен выглядеть так:

 "4" is missing after "1 e 2 f 3"

ИЛИ только (еще лучше):

"1 e 2 f 3"

2 ответа2

0

sed не правильный инструмент для работы. Тем не менее, мы, вероятно, все еще можем сделать это в sed:

sed -n '/^ 1 .* 2 .* 3$/,/^ 5$/ { /^ 1 .* 2 .* 3$/ { h }; /^ 4$/ { x; s/.*//; x;}; /^ 5$/ { x; p; x} }' filename | grep -v -e '^$'

Вот только часть, которую я добавил в ваш блок диапазона:

/^ 1 .* 2 .* 3$/ { h }; /^ 4$/ { x; s/.*//; x;}; /^ 5$/ { x; p; x}

Прочитайте это как:

если строка соответствует регулярному выражению /^ 1 .* 2 .* 3$/ , затем h (сохранить строку в буфер хранения)
если строка соответствует регулярному выражению /^ 4$/ , то x (обменный буфер, т. е. операции make, применяемые для буфера хранения, а не стандартного буфера), затем заменить все в буфере удержания *, затем снова x (чтобы переключиться обратно в стандартный буфер)
если строка соответствует ^ 5$/ , тогда переключитесь на буфер хранения, p (выведите содержимое буфера хранения) и вернитесь к стандартному буферу

* К сожалению, s/.*// не удаляет строки в буфере удержания. Удаление строк в буфере удержания кажется трудным, поэтому мы избавляемся от них, добавляя вместо этого grep -v -e '^$' .

Обновить

Эта версия печатает имя файла после совпадения (используя команду F ) и управляет без привязки к grep . Спасибо, Пауло!

sed -n '/^ 1 .* 2 .* 3$/,/^ 5$/ { /^ 1 .* 2 .* 3$/ { h }; /^ 4$/ { x; s/.*//; x;}; /^ 5$/ { x; /^$/ !{ p; F }; x} }' data
0

Спасибо @sneep за упоминание perl:

perl -lane 'if($n=/^ 1 .* 2 .* 3$/../^ *5$/) {$s=$_ if $n==1; $s="" if /^ *4$/; print "$ARGV: $s" if $s && $n=~/E/}' /otherdir/*

Я надеюсь, что правильно понимаю проблему: пожалуйста, добавьте в OP, чтобы уточнить любые дальнейшие детали.

Объяснение:

• Практический язык извлечения и отчетности perl .
-lane переключатели обычно полезны для однострочников.
' начало фактических программных инструкций
if(/^ 1 .* 2 .* 3$/../^ *5$/) { выполнять действия между фигурными скобками только для фрагментов текста, начинающихся со строки, совпадающей с /^ 1 .* 2 .* 3$/ и заканчиваются строкой, которая содержит одну 5 цифру, возможно, с предшествующим любым количеством пробелов.
$n=/^ 1 .* 2 .* 3$/../^ *5$/ отслеживать номер строки в текстовой части.
$s=$_ if $n==1; сохранить первую строку текстовой части в переменной $s .
$s="" if /^ *4$/; ищите желаемую строку: одну 4 цифру, которая идет после любого количества пробелов Если найдено, удалите ранее сохраненную строку для переменной $s .
print "$ARGV: $s" if $s && $n=~/E/ напечатать имя файла, двоеточие, пробел и строку, с которой начинается текущая часть текста, если переменная $s содержит какой-либо текст и $n Счетчик показывает, что была достигнута последняя строка текстовой части.
} конец действий, которые должны быть выполнены над текстовой частью.
' конец инструкции программы.
/otherdir/* обработать все файлы в пути /otherdir/

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .