Печать строк между двумя регулярными выражениями с помощью 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'