Likely your issue is the z flag to GNU grep which then changes of the definition of a line to terminated by a \0
Easy to demo. Given:
$ echo "$txt"
line 1
line 2
line 3
line 4
line 5
word ...other text
phrase ...yet another text
line 6
line 7
line 8
line 9
line 10
You can do:
$ echo "$txt" | ggrep --context=2 -Pz "word|phrase"
# prints all the lines
Or:
$ echo "$txt" | ggrep --context=2 -P "word|phrase"
line 4
line 5
word ...other text
phrase ...yet another text
line 6
line 7
Which you can demonstrate will work with z by actually have NUL terminations for the lines:
$ echo "$txt" | tr '\n' '\0' | ggrep --context=2 -Pz "word|phrase" | tr '\0' '\n'
line 4
line 5
word ...other text
phrase ...yet another text
line 6
line 7
For perl regex's and logic of before and after and multilines, you might as well just use Perl!
Given:
$ cat file
line 1
line 2
line 3
line 4
line 5
word ...other text
betweener 1, line 7
betweener 2, line 8
phrase ...yet another text
line 10
line 11
line 12
line 13
line 14
You can do:
# $b=2 is equivalent to grep -B 2, or lines before
# $a=2 is equivalent to grep -A 2, or lines after
$ perl -lne 'BEGIN{$b=2; $a=2;}
print join("\n", @a) if (/word/);
print if (/word/../phrase/) || ($c && $c--);
$c=$b if (/phrase/);
shift @a if push(@a, $_)>$a;' file
Or, you can use POSIX or GNU awk as well:
$ awk 'BEGIN{b=2; a=2}
/word/ { for (i=FNR-b;i<=FNR-1;i++)
print arr[i] # print the lines before the first match
f=1} # flag we are in the match
f || (c && c--) # print either if in the match or tail context
/phrase/ {f=0; c=a} # end match, start tail
{for (ln in arr)
if (ln<FNR-b) delete arr[ln] # rolling line buffer
arr[FNR]=$0} # save current line
' file
Either prints:
line 4
line 5
word ...other text
betweener 1, line 7
betweener 2, line 8
phrase ...yet another text
line 10
line 11
That works even with no 'betweener' lines.