Try:
$ awk 'f{hdg=$0; f=0} /errors|warning/{if(hdg){print hdg; hdg=""}; print} /START/{f=1}' file
Heading1
errors
Heading3
errors
How it works
f{hdg=$0; f=0}
If f
is true (nonzero), then save the current line in the variable hdg
and set f
back to zero.
/errors|warning/{if(hdg){print hdg; hdg=""}; print}
If the current line contains errors
or warning
, then, if the variable hdg
is non-empty, print it. Also, print the current line.
/START/{f=1}
If the current line contains START
, then set variable f
to one.
Multiline version
For those who prefer their commands spread over multiple lines:
awk '
f {
hdg=$0
f=0
}
/errors|warning/{
if(hdg){
print hdg
hdg=""
}
print
}
/START/{
f=1
}' file
Variation: Add a blank line before heading
If we want a blank line to separate the output:
$ awk 'f{hdg=$0; f=0} /errors|warning/{if(hdg){print nl hdg; hdg=""; nl="\n"}; print} /START/{f=1}' file
Heading1
errors
Heading3
errors
Variation: Ignore errors/warnings after an END line
$ awk 'f{hdg=$0; f=0} g && /errors|warning/{if(hdg){print nl hdg; hdg=""; nl="\n"}; print} /START/{f=1; g=1} /END/{g=0}' file
Heading1
errors
Heading3
errors
To make the above case insensitive (GNU awk):
awk 'BEGIN{IGNORECASE=1} f{hdg=$0; f=0} g && /errors|warning/{if(hdg){print nl hdg; hdg=""; nl="\n"}; print} /START/{f=1; g=1} /END/{g=0}' file
grep -v -e "START" -e "END" -e "errors" input.txt