3

I have a file roughly like

header_one
param1
param2
...

data_one
data1
data2
data3
data4
...

header_two
param1
param2
...

data_two
data1
data2
data3
data4

I'd like to extract all header blocks with N following lines and all data blocks with M != N following lines, keeping the order in which they appear in the file and discarding everything else.

If M == N == 8 I could e.g. do

grep -A8 -E "header_|data_"

But what if I want to have different context for each pattern?

2 Answers 2

3

An ad-hoc solution with awk could be something like this:

awk '/^header_/ {n=1+1} /^data_/ {n=1+2} n-- > 0; n == 0 {print "---"}' < file

n is set on matching lines, and is decremented for each line. The lines are printed when n is positive with a separator after each block. With the above values, it would print header_ lines plus one next line, and data_ lines plus two next lines.


If the context blocks can overlap, the new value of n will override the previous value. To prevent that, add conditions to guard the assignments:

awk '/^header_/ {if (n < 2) n=2} 
     /^data_/   {if (n < 5) n=5}
     n-- > 0; n == 0 {print "---"}' < file

That should be better at handling cases where there's data_ and header_ on consecutive lines.

2
  • amazing, and also easy to extend to more complex parsing... I should definitely study awk sooner than later
    – filippo
    Commented Jun 19, 2018 at 8:01
  • 2
    @filippo, well, the "after" context is easy... the "before" context is more work since it needs remembering past input. And even trickier if the blocks can overlap.
    – ilkkachu
    Commented Jun 19, 2018 at 8:13
3

I have tried with below sed command As tested it worked fine let me know for any confusions

sed -n -e  '/header_/,+1p' -e '/^data_/,+2p' filename

output

header_one
param1
data_one
data1
data2
header_two
param1
data_two
data1
data2
2
  • One difference from grep is handling overlapping matches. Say if data_one immediately followed header_one, it would be printed twice — once as part of /header_/,+1 address range, once as part of /^data_/,+2 range. Commented May 17, 2023 at 8:27
  • Numbering the lines with cat filename | nl | sed -n -e '/\theader_/,+1p' -e '/\tdata_/,+2p' helps figure out where lines were skipped (and where they're printed twice)... Commented May 17, 2023 at 8:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .