1

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

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
    Jun 19 '18 at 8:01
  • 1
    @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
    Jun 19 '18 at 8:13
2

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.