Note that the lines could occur immediately after one another and I would like to have output print only once in such cases.
To avoid this, a solution using vec could work for you.
The line of code vec($vec, $_, 1) ||= 1 for $lo .. $hi; would assign a 1 to each position. So you wouldn't repeat a line when printing out the results.
my @log_lines=<$read_tmp_log>;
my $vec = '';
for my $i (0..$#log_lines) {
next unless lc($log_lines[$i]) =~ /error|fatal|critical/;
my $lo = $i - 5 < 0 ? 0 : $i - 5;;
my $hi = $i + 5 > $#log_lines ? $#log_lines : $i + 5;
vec($vec, $_, 1) ||= 1 for $lo .. $hi;
}
my $newline_needed = 0;
for my $i (0 .. $#log_lines) {
if (vec($vec, $i, 1) == 1) {
print $log_lines[$i];
$newline_needed ||= 1;
}
else {
print "\n" if $newline_needed;
$newline_needed = 0;
}
}