grep output of a text file

Hi. I have a unix script 'if' condition that greps through a file and searches for the strings ERROR and WARNING.

if egrep -q 'ERROR|WARNING' myfile.txt; then 

When this 'if' condition is true then I want to be able to capture 10 lines before the string and 10 lines after the string. So a total of only 20 lines.

Can anyone help me with a way to grep through a files and then output only 20 lines of the file (10 before the string - 10 after) that surround the string when it's found?

Any help would be greatly appreciated!

grep -A 10 -B 10 -E 'ERROR|WARNING' myfile.txt  

?

Hmm, just returning:

grep -A 10 -B 10 -E 'ERROR' myfile.txt
grep: Not a recognized flag: A

Getting lines after it is doable since grep has a special option to help with that, -m. That will cause it to stop reading after the number of matches you tell it.

#!/bin/sh

# open the file
exec 5<filename

# Read up to the first match.
# because of -m, grep will leave the open file on the line after it.
# Then print 10 more lines.
( grep -m 1 "MATCH" && head -n 10 ) <&5

# close the file
exec 5<&-

Getting the lines before it is much harder, since a shell can't seek backwards.

---------- Post updated at 11:18 AM ---------- Previous update was at 11:17 AM ----------

You never said what your system was. That's a GNU option and I guess you don't have GNU.

Hmm...my system is AIX 5.3. Is this what you mean? Does this help?

Yes, it means you don't have GNU grep, that's usually found in Linux, though occasionally installed elsewhere as a third-party app for its convenient options. Here's a brute-force non-GNU solution.

#!/bin/ksh

TMP="/tmp/$$"

while read LINE
do
        if [[ "${LINE}" == *ERROR* ]] || [ "${LINE}" == *WARNING* ]]
        then
                tail -n 10 "$TMP"
                echo "$LINE"
                head -n 10
                : > "$TMP"
        else
                echo "$LINE" >> "$TMP"
        fi
done < inputfile

rm -f "$TMP"

It's not perfect. If more than one error happens within the 10 lines it might not capture all the context.

---------- Post updated at 11:47 AM ---------- Previous update was at 11:32 AM ----------

#!/bin/ksh

TMP="/tmp/$$"

CONTEXT=0

while read LINE
do
        if [[ "${LINE}" == *ERROR* ]] || [ "${LINE}" == *WARNING* ]]
        then
		[[ "${CONTEXT}" -le 0 ]] && tail -n 10 "$TMP"
		CONTEXT=10
        fi

	if [[ "${CONTEXT}" -gt 0 ]]
	then
		echo "${LINE}"
	fi

        echo "${LINE}" >> "$TMP"

	((CONTEXT--))

done < inputfile

rm -f "$TMP"

This one should make better output, but is slower.

1 Like

or try this one :