Grep, начиная с фиксированного текста, до первой пустой строки

9

У меня есть файл, prova.txtкак это:

Start to grab from here: 1
fix1
fix2
fix3
fix4
random1
random2
random3
random4

extra1
extra2
bla

Start to grab from here: 2
fix1
fix2
fix3
fix4
random1546
random2561

extra2
bla
bla

Start to grab from here: 1
fix1
fix2
fix3
fix4
random1
random22131

и мне нужно перейти от «Начать захватывать здесь» до первой пустой строки. Вывод должен быть таким:

Start to grab from here: 1
fix1
fix2
fix3
fix4
random1
random2
random3
random4

Start to grab from here: 2
fix1
fix2
fix3
fix4
random1546
random2561

Start to grab from here: 1
fix1
fix2
fix3
fix4
random1
random22131

Как вы можете видеть, строки после «Начать захватывать здесь» случайны, поэтому флаг -A -B grep не работает:

cat prova.txt | grep "Start to grab from here" -A 15 | grep -B 15 "^$" > output.txt

Можете ли вы помочь мне найти способ, который поймает первую строку, которая будет захвачена (как «Начать захватывать отсюда»), до пустой строки. Я не могу предсказать, сколько случайных строк у меня будет после «Начать отсюда».

Любое решение, совместимое с Unix, приветствуется (grep, sed, awk лучше, чем perl или аналогичный).

Отредактировано: после блестящего ответа @ john1024, я хотел бы знать, возможно ли:

1 ° Сортировка блока (в соответствии с Start начать отсюда: 1, затем 1, затем 2).

2 ° удалить 4 (в алфавитном порядке) строки fix1, fix2, fix3, fix4, но всегда 4

3 ° в конечном итоге удалить случайные дубликаты, такие как команда sort -u

Окончательный результат должен быть таким:

# fix lines removed - match 1 first time
Start to grab from here: 1
random1
random2
random3
random4

#fix lines removed - match 1 second time
Start to grab from here: 1
#random1 removed cause is a dupe
random22131

#fix lines removed - match 2 that comes after 1
Start to grab from here: 2
random1546
random2561

или

# fix lines removed - match 1 first time and the second too
Start to grab from here: 1
random1
random2
random3
random4
#random1 removed cause is a dupe
random22131

#fix lines removed - match 2 that comes after 1
Start to grab from here: 2
random1546
random2561

Второй вывод лучше первого. Нужна какая-то другая магия команд Unix.

heisen
источник
1
Это действительно полезно для получения трассировки стека для определенного потока из вывода java jstack. Рад, что нашел это Q & A!
Бенджамин

Ответы:

13

Использование awk

Пытаться:

$ awk '/Start to grab/,/^$/' prova.txt
Start to grab from here: 1
random1
random2
random3
random4

Start to grab from here: 2
random1546
random2561

Start to grab from here: 3
random45
random22131

/Start to grab/,/^$/определяет диапазон. Он начинается с любой совпадающей строки Start to grabи заканчивается первой пустой строкой, ^$следующей за ней.

Используя sed

С очень похожей логикой:

$ sed -n '/Start to grab/,/^$/p' prova.txt
Start to grab from here: 1
random1
random2
random3
random4

Start to grab from here: 2
random1546
random2561

Start to grab from here: 3
random45
random22131

-nговорит sed не печатать ничего, если мы явно не попросим об этом. /Start to grab/,/^$/pговорит ему напечатать любые строки в диапазоне, определенном /Start to grab/,/^$/.

John1024
источник
Ваше решение идеально, я отредактировал мою просьбу добавить что-то. По-настоящему ценю вашу помощь. Спасибо
Heisen
1

Я публикую альтернативное решение, так как оно может быть полезно для некоторых людей. Это решение не полностью соответствует заявленным требованиям, для лучшего решения см. Ответ @ John1024.

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

$ awk '/Start/' RS= prova.txt 
Start to grab from here: 1
fix1
fix2
fix3
fix4
random1
random2
random3
random4
Start to grab from here: 2
fix1
fix2
fix3
fix4
random1546
random2561
Start to grab from here: 1
fix1
fix2
fix3
fix4
random1
random22131

Эта версия не сохраняет пустые символы новой строки в выводе. Он также покажет контекст перед совпадением, если он присутствует. Такое поведение может быть очень полезным, когда нужно найти что-то в файле, и вы хотите увидеть разделенный строкой блок, частью которого он является, например:

$ awk '/random1546/' RS= prova.txt 
Start to grab from here: 2
fix1
fix2
fix3
fix4
random1546
random2561

Например, я считаю это полезным при поиске вещей в iniфайлах.

Htaccess
источник