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 :) <toc> === 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). {{{ awk $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 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: {{{ awk $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): {{{ awk++ $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 } }}}
Summary:
This change is a minor edit.
Username: