Start_pattern
abc
d End_pattern
Start_pattern
abc
d
ef
ghij
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern
Start_pattern
abc
dhi
jklm End_pattern
Just for completeness I add the sed
solution here :
sed -n '/Start_pattern/{:a;N;/End_Pattern/!ba;/ef/p}'
To understand this, you need to think of labels and branches as goto statements
Start_pattern
is found execute what is between {...}
a
with :a
N
)End_Pattern
is found do not goto label a
(!ba
)End_Pattern
is found, execute the last part which states that if the full record contains ef
, print the record.adapting from my answer on another site - Get text between start pattern and end pattern based on pattern between start and end pattern
$ awk '/Start_pattern/{f=1; m=0; buf = $0; next}
/ef/ && f{m=1}
f{buf = buf ORS $0}
/End_pattern/ && f{f=0; if(m==1)print buf}
' ip.txt
Start_pattern
abc
d
ef
ghij
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern
/Start_pattern/{f=1; m=0; buf = $0; next}
set flag to indicate start of block, clear match, initialize buffer and move on to next line/ef/ && f{m=1}
if line contains ef
, set match. f
is used to avoid matching ef
outside of Start_pattern...End_pattern
f{buf = buf ORS $0}
as long as flag is set, accumulate input lines/End_pattern/ && f{f=0; if(m==1)print buf}
at end of block, print buffer if match was found $ cat tst.awk
/Start_pattern/ { fnd=1; buf="" }
fnd {
buf = buf $0 ORS
if (/End_pattern/) {
if (buf ~ /ef/) {
printf "%s", buf
}
fnd = 0
buf = ""
}
}
$ awk -f tst.awk file
Start_pattern
abc
d
ef
ghij
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern
With gawk
, which supports multi char RS
:
gawk 'BEGIN{RS=ORS="End_pattern"}/ef/' file
Output:
Start_pattern
abc
d
ef
ghij
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern
Explanation:
# Split records based on the End_pattern
BEGIN{RS=ORS="End_pattern"}
# Print records that contain the search term
/ef/
Btw, for cosmetic reasons you might want to append a newline at the end out the output:
gawk 'BEGIN{RS=ORS="End_pattern"}/ef/;END{printf "\n"}' file
PS: While the above solution works with gawk
only, it is also possible to achieve that with a simple awk
script which is compatible to POSIX, meaning it works with any awk
:
awk '{b=b$0"\n"}/End_pattern/{if(b~/ef/){printf "%s",b};b=""}' file
Explanation:
# Append the current line plus a newline to b(uffer)
{b=b$0"\n"}
# Once End_pattern is found ...
/End_pattern/{
# Check if the buffer contains the search term
if(b~/ef/){
# Print the buffer when the term was found
printf "%s",b
}
# Clear the buffer
b=""
}
awk '{b=b$0"\n"}/End_pattern/{if(b~/ef/){printf "%s",b};b=""}' file