Печать строк между двумя регулярными выражениями с помощью sed

У меня есть текстовый файл, который содержит несколько разделов, и я хочу напечатать один из этих разделов.

Часть файла выглядит как

3. line 3
4. line 4

## Screenshots ##

1. line 1
2. line 2
3. line 3
4. line 4

## Changelog ##

3. line 3
4. line 4

Из этого я хочу получить все строки между ## Screenshots ## и началом следующего раздела. Здесь следующий раздел ## Changelog ##, но это может быть что угодно. Единственное, на что мы можем зависеть, это то, что он начнется с ##.

Из другого потока, я нашел следующий код

sed -e "H;/${pattern}/h" -e '$g;$!d' $file

который я изменил до

sed -e "H;/## Screenshots ##/h" -e '$g;$!d' readme.md

Теперь он извлекает все строки, начиная с ## Screenshots ##, но печатает все строки до конца файла.

Затем я передал его в другой sed, например

sed -e "H;/## Screenshots ##/h" -e '$g;$!d' readme.md | sed "/^##/q" 

Но теперь он печатает только

## Screenshots ##

В любом случае я могу распечатать все строки в разделе скриншотов?

Ответ 1

awk '/pattern/{p=1;print;next} p&&/^##/{p=0};p' file

возьмите "Скриншот" в качестве примера:

kent$  awk '/^## Screenshot/{p=1;print;next} p&&/^##/{p=0};p' file
## Screenshots ##

1. line 1
2. line 2
3. line 3
4. line 4

EDIT добавить объяснение

awk '/^## Screenshot/{p=1;print;next} : if match pattern, set p=1,print the line,read next line,(stop processing following scripts)
p&&/^##/{p=0}                         : if p==1 and match /##/ again (next section), set p=0
;p' file                              : if p==1, print the line

только sed

sed -n '/## Screensh/,/##/{/Scree/{p;n};/##/{q};p}' file

EDIT2 добавить объяснение в sed cmd

-n                 -> not print
'/## Screen/, /##/ -> match range, I guess you knew it already
{                  -> if in this range
    /Scree/        -> and line matches /Screenshot/
        {p;n};     -> do print line, and read next row (skip doing rest processing)
    /##/           -> if line matches "##"
        q;         -> quit, we have done all printing
    p              -> if we come to here, print the line
}

Ответ 2

sed -n '/## Screenshots ##/,/##/p' readme.md

Это начнет печатать с ## Screenshots ## до следующего ##. Если вы не хотите последнего совпадения ##, проще всего

sed -n '/## Screenshots ##/,/##/p' readme.md |head -n-1

Ответ 3

AWK

Это можно сделать более легко и более универсально с помощью awk:

awk '/^##/ { p-- } /^## Screenshots/ { p=1 } p>0' infile

Если вам нужен только один раздел, это будет делать:

awk '/^##/ { p=0 } /^## Screenshots/ { p=1 } p' infile

Вывод:

## Screenshots ##

1. line 1
2. line 2
3. line 3
4. line 4

Объяснение

/^##/ { p-- }               # subtract one from the section counter
/^## Screenshots/ { p=1 }   # set section counter if current line has Screenshot 
p>0                         # print line if section counter greater than 0

СЕПГ

sed -n '/^## Screenshots/,/^##/p' infile | sed '$d'