context-grep

Leo de Wit leo at philmds.UUCP
Sat Feb 11 23:49:52 AEST 1989


In article <2017 at piraat.cs.vu.nl> maart at cs.vu.nl (Maarten Litmaath) writes:
|How about `sed'? I think Leo de Wit [a.k.a. Mr. Sed] will have some remarks
|about `cgrep', but it's a start.

Ah, you asked for it!
I looked at Maarten's script and modified some of it. The result is
appended below. Modifications:

1) Changed use of [ by case whenever possible, 'cause this is a builtin.
2) Changed while-test-expr loops to construct a repeated pattern ($before
and $after) by a yes|sed construct. Neat trick, if I may say so myself (8-).
3) Changed the sed expression, since it didn't handle well an appearance
of $pattern in the 'after pattern part' (was treated as an ordinary line).
4) Prepend each line output by <filename>:, this is perhaps more in the
style of grep. It also obviates the need of a temporary file. This however
is clearly a matter of taste.

Ad 2): if your system doesn't support yes (a never ending echo), you can
build it easily from echo and sed:

echo $*|sed '
: again
	p
	b again'

yes and sed also make for an easy range generator (this was also in this
newsgroup, where someone wanted to create ranges without using a C program)
($1 and $2 are respectively the first and last number to be generated):

yes|sed -n "$1,$2{;=;$2q;}"

     Leo.


P.S. The modified cgrep follows here:
-------------------------------
#! /bin/sh

# cgrep		- context grep
#
# grep pattern plus surrounding lines
# @(#)cgrep 1.1 89/01/18 Maarten Litmaath
#      modified 89/02/11 Leo de Wit
#
# example: "cgrep -5 +0 '^{' *.c" shows all function headers in the C sources,
# with (max.) 5 lines preceding the `{', followed by 0 lines (no line will be
# printed twice; there might not be as many contextual lines as requested)
# each line is prepended with the filename it appears in, followed by a colon.
# cgrep can be used as a filter; the file name will be `STDIN'
# the `--' option can be used to `protect' a pattern starting with `-'

usage="Usage: cgrep [-<# before>] [+<# after>] [--] <regexp> [<files>]"

case $# in 0) echo "$usage"; exit 1;; esac

b=2 a=2

while :
do
	case $1 in
		--)
			shift
			break
			;;
		-*)
			b=`echo "x$1" | sed s/..//`
			shift
			;;
		+*)
			a=`echo "x$1" | sed s/..//`
			shift
			;;
		*)
			break
	esac
done

case $# in 0) echo "$usage"; exit 1;; esac

pattern=`echo "$1" | sed 's-/-\\\/-'`
shift

case $b in "") b=1;; esac
case $a in "") a=1;; esac

case $b in
0) branch=b;;
*)
	case "$pattern" in
		\^*)
			pattern=`echo "$pattern" | sed 's/./\\\n/'`
	esac
	before=`yes "\n[^\n]*"|sed -n "
		: back
		$b{
			s/\n//g
			p
			q
		}
		N
		b back"`;;
esac

case $a in
0) after= ;;
*) after=`yes "\n[^\n]*"|sed -n "
	: back
	$a{
		s/\n//g
		p
		q
	}
	N
	b back"`;;
esac

case $# in
0) files=STDIN
   set dummy;;
*) files="$*"
   set dummy $*;;
esac

umask 077

for i in $files
do
	shift

# The hold space will hold (at most) b lines (if not in the pattern part)
# CLRHLD (Clear hold space) and ADJUST (trim number of lines in hold space)
# are 'in hold space context', NEXT is 'in pattern space context'.

	sed -n "/$pattern/{
			x
			/^\n/{
				s/^\n/$i:/
				s/\n/&$i:/g
				p
			}
			x
		: CLRHLD
			x
			s/.*//
		: NEXT
			x
			s/^/$i:/p
			n
			/$pattern/b CLRHLD
			H
			x
			/\n[^\n]*$after/!b NEXT
			a\\
				-----
			b ADJUST
		}
		H
		x
	: ADJUST
		s/.*\($before\)/\1/
		x
		" $1
done
-------------- ends here -------------



More information about the Comp.unix.questions mailing list