grep to return Nth and Mth lines before and after the match

If:

cat file
a
b
c
d
e
f match
g
h
i match
j
k
l
m
n
o

Then:

awk '
    {line[NR] = $0} 
    /match/ {matched[NR]} 
    END {
        for (nr in matched)
            for (n=nr-5; n<=nr+5; n+=5) 
                print line[n]
    }
' file
a
f match
k
d
i match
n

This is basically Glenn's solution, but implemented with Bash, Grep, and sed.

grep -n match file |
    while IFS=: read nr _; do
        sed -ns "$((nr-5))p; $((nr))p; $((nr+5))p" file
    done

Note that line numbers less than 1 will make sed error, and line numbers greater than the number of lines in the file will make it print nothing.

This is just the bare minimum. To make it work recursively and handle the above line number cases would take some doing.


It can't be done with only grep. If ed's an option:

ed -s file << 'EOF' 
g/match/-5p\
+5p\
+5p
EOF  

The script basically says: for every match of /match/, print the line 5 lines before that, then 5 lines after that, then 5 lines after that.