Path: utzoo!utgpu!utstat!jarvis.csri.toronto.edu!mailrus!ames!ucsd!ucsdhub!hp-sdd!ncr-sd!ncrlnk!uunet!mcvax!hp4nl!philmds!leo From: leo@philmds.UUCP (Leo de Wit) Newsgroups: comp.unix.questions Subject: Re: context-grep Keywords: grep Message-ID: <947@philmds.UUCP> Date: 11 Feb 89 13:49:52 GMT References: <9176@burdvax.PRC.Unisys.COM> <2017@piraat.cs.vu.nl> Reply-To: leo@philmds.UUCP (Leo de Wit) Organization: Philips I&E DTS Eindhoven Lines: 164 In article <2017@piraat.cs.vu.nl> maart@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 :, 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>] [--] []" 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 -------------