Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
632 views
in Technique[技术] by (71.8m points)

unix - Print lines between two regex using sed

I have a text file which contains multiple sections and I want to print one of those sections.

Part of the file looks like

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

From this I want to retrieve all lines between ## Screenshots ## and the starting of the next section. Here the next section is ## Changelog ##, but it could be anything. So the only thing which we can depend on is that it will start with ##.

From another thread, I found the following code

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

which I modified to

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

Now, it retrieves all lines starting from ## Screenshots ##, but it prints all lines till the end of the file.

I then piped it to another sed like

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

But now it prints only

## Screenshots ##

Is there anyway I can print all lines in the screenshots section?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
awk '/pattern/{p=1;print;next} p&&/^##/{p=0};p' file

take the "Screenshot" as example:

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 add explanation

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 only

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

EDIT2 add explanation to 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
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...