1

I know how to use the range operator in awk

awk '/start/,/stop/' file

Is it possible to select text inside the range operator? ATM, I am using an if statement

awk '/start/,/stop/ { if ($1~/foo/) { } }' file

is there a more idomatic way of doing it?

NinjaGaiden
  • 3,046
  • 6
  • 28
  • 49

2 Answers2

1

Never use a range expression as it makes trivial jobs very slightly briefer but then requires a complete rewrite or duplicate conditions when the task gets slightly more interesting.

Instead of:

awk '/start/,/stop/' file

Use:

awk '/start/{f=1} f{print} /stop/{f=0}' file

and then what you want to do becomes simply:

awk '/start/{f=1} f{ if ($1~/foo/) { } } /stop/{f=0}' file

I'm assuming you have something in mind for inside the empty { }.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

Well what you have proposed does work:

$ seq 1 15 | awk '/^6/,/^9/ { if ($1~/8/){print} else print "in range but not 8" }'
in range but not 8
in range but not 8
8
in range but not 8

But as Ed Morton states, it is a brittle construct.

Example, the , is the lowest precedence and you may scratch your head over why this does not work:

$ echo "this one print" | awk '/^1/ , /^55/ || /this/'  

Another example. Suppose you have:

$ echo "a
b
c
---
d
e
f
---
g
h"

Try and use a range operator to include or exclude everything between ---. It is tricky since the start and end marks are the same and it is possible to set and reset a range on the same line.

When if you train you muscle memory to not do /^x/ , /^y/ and instead do /^x/{flag=1} flag{whatever} /^y/{flag=0} then no more head scratching:

$ echo "this one print" | awk '/^1/{flag=1} flag || /this/{print} /^55/{flag=0}'
this one print

Or,

$ echo "a
b
c
---
d
e
f
---
g
h" | awk '/^---$/{f= ! f; next}  f'
d
e
f

(Just change to ! f at the end if you want to reverse from include to exclude...)

So in general, you can do this for a range and subrange:

awk '/^start/ || /^end/{f= ! f; next} /e/ && f { what you do in sub range }' file

         ^         ^                            can be a single regex if same pattern
                                 ^              remove next to include in processing
                                      ^         applies to within range /start/,/end/
                                          ^  ^     because of the flag
Community
  • 1
  • 1
dawg
  • 98,345
  • 23
  • 131
  • 206