With grep I know how to set the context to a fixed number of lines. Is it possible to show a context based on an arbitrary string condition, like set after-context to "until the next blank line"?
Or possibly some other combination of tools?
Basically I have a log file of contiguous lines, with blank lines separating the "events" I want to search for a string in the log file, but show the whole event....
It sounds like you need sed
:
sed -n '/pattern/,/^$/p' file
Don't print by default (-n
). For lines that match /pattern/
up to an empty line /^$/
, print.
A simple solution is:
awk '/pattern/' RS= input-file
Setting RS to the empty string makes awk treat blank lines as the record separator, and the simple rule /pattern/
causes awk to print any record that matches the pattern, which can be any extended regular expression.
Here's a (tested) awk
solution, separated onto multiple lines for readability:
awk '/pattern/ {do_print=1}
do_print==1 {print}
NF==0 {do_print=0}' input_file
This script will also print the blank line so it's easier to visually separate the different matched blocks. If you don't want the blank line, swap the 2 lines do_print==1 {print}
and NF==0 {do_print=0}
Explanation:
awk
: invoke the awk
tool - it evaluates the input one line at a time sequentially.
'...'.
: everything enclosed by the single quotes is given to awk
as instructions. In this case we perform the quoted instructions on each line.
/pattern/ {do_print=1}
: whenever a line contains "pattern
", turn on the do_print
flag
do_print==1 {print}
: if the do_print
flag is set to on, print the current line.
NF==0 {do_print=0}
: NF stands for Number of Fields. awk
delimits each line by spaces and tabs by default to break a line into fields. In this case trivially a blank line has no fields - so we turn off the do_print
flag to stop printing when we see a line with NF == 0
Personally I like the answer from @William Pursell as the before context is often useful (eg when grepping for things in ini
files). If you actually want only the after context with awk
you can do this:
$ cat demo.ini
[foo]
aaa = 1
bbb = 2
ccc = 3
[bar]
eee = 8
fff = 0
ggg = 1
[baz]
xxx = 1
yyy = 0
zzz = 2
$ awk '/bar/,/^$/' demo.ini
[bar]
eee = 8
fff = 0
ggg = 1
$ awk '/fff/,/^$/' demo.ini
fff = 0
ggg = 1
$
Compare with the RS=
version:
$ awk '/bar/' RS= demo.ini
[bar]
eee = 8
fff = 0
ggg = 1
$ awk '/fff/' RS= demo.ini
[bar]
eee = 8
fff = 0
ggg = 1