ContextGrep

The following snippets print matching lines with surrounding context lines, like GNU grep's grep -A N (N lines after), grep -B N (num lines before), and grep -C N (num lines before and after), and all in about double the time :)

Lines After

Printing the match followed by N lines is the easiest and fastest, since we don't have to save any lines. The following expects two variables to be set: Pattern (a regex to match), and After (the number of lines to print after each match).

$0 ~ Pattern {                       # if we found the pattern ...
    if (seen++ && NR>afterlineno+1)  # if we already found another block   
                                     # and are outside a context block
        print "--"                   # ... print a divider
    afterlineno = NR + After
}

NR <= afterlineno

Or as a oneliner (3 lines of context, with "Regex" as pattern):

awk -v N=3 '/Regex/{if (seen++ && NR>a+1)print "--"; a = NR+N} NR<=a'

Lines Before

Printing N lines before a match is trickier and slower, because we need to save lines, as we don't know yet whether they should be printed. It's possible to minimize the number of lines saved by deleting extra saved lines as you read the file, but this slows down the process significantly. Here's a way of doing it (this time, the script expects the variables Pattern and Before (number of lines before) to be set:

$0 ~ Pattern {
    if (lineno && (last+Before+1)<NR)    # if we already printed a block
                                         # and not within a block
        print "--"                       # ... print a divider
    lineno = NR-Before                   # set the array index to start printing
    if (lineno<last)                     # check if contexts overlap
        lineno = last+1
    for ( ; lineno < NR; lineno++)
        if (lineno in lines)
            print lines[lineno]
    print
    last = NR
    next
}

{
    lines[NR] = $0     # ... or save the line
}

The variable last keeps track of the last line printed, so lines are not repeated when contexts overlap.

Lines Before and After

The following combines the two previous scripts. This script expects the variables Pattern and Context (number of lines to print before and after a match):

$0 ~ Pattern {
    afterlines = NR + Context
    if (seen++ && (last+Context+1)<NR)
        print "--"
    lineno = NR-Context
    if (lineno<last)
        lineno = last+1
    for ( ; lineno < NR; lineno++)
        if (lineno in lines)
            print lines[lineno]
}

NR <= afterlines {
    print
    last = NR
    next
}

{
    lines[NR]=$0
}