Sed Context Grep

OK. A slight rethink wherein the hold space acts similarly to a three-line FIFO stack, except that the lines are all retrieved at once and only the last two are put back before another is added. The stack is output complete if its penultimate line contains “ain”, with adjustments at the last line. It seems to work.

set t to quoted form of "The brain
rain
drain
in
Spain
stays
mainly
in
the
Staines
plain
again
Jane

again"

set cmd to "echo " & t & " | sed -En '
# Move the first line to the "stack" (hold space)
1 h
# With each of the following lines in turn:
1 !{
	# Append the line to the stack and retrieve the stack contents.
	H
	g
	# If the penultimate retrieved line contains "ain", print them all and, if not at the last line of text, output a separator.
	/ain[^[:cntrl:]]*\\n[^[:cntrl:]]*$/ {
		p
		$ !i\\'$'\\n''---
	}
	# If three lines were taken from the stack, lose the first one and push the other two back.
	/^[^[:cntrl:]]*\\n([^[:cntrl:]]*\\n[^[:cntrl:]]*)$/ {
		s//\\1/
		h
	}
}
# At the last line of the text, after the above processes, the pattern space contains either the first line (if there's only one) or the last two (the edited stack contents).
$ {
	# If the line contains "ain":
	/ain[^[:cntrl:]]*$/ {
		# If there's a line before it also containing "ain", output another separator.
		/ain[^[:cntrl:]]*\\n/ i\\'$'\\n''---
		# Print the pattern space contents.
		p
	}
}'"

do shell script cmd

Edit: Comments revised.

:frowning: The lines aren’t numbered. :lol:

Just kidding. It’s just Brilliant!:cool:

Actually, I figured, I could write what I wanted faster in sed, and implement it in a shell script, rather than write it in c. (The sole intent is to have a tool to trace a variable/function call throughout a source code file.)

What I want, is a short context, and that the context is to be broken, when a new match appear, and I want line numbers.

Given the latest “poem” from the post above, the output looks like this:

[code] 1 The brain

 2	rain

 3	drain
 4	in

 5	Spain
 6	stays

 7	mainly
 8	in

 9	the
10	Staines

11	plain

12	again
13	Jane

14	
15	again"[/code]

I implemented it as a shell script, which should be easy to use from a do shell script, the regexp is given as a parameter quoted with double quotes on the commandline, and the input must be redirected into it.

[code]#!/bin/bash
if [ $# -ne 1 ] ; then
echo "Usage: cgrep "pattern" <input

Prints 1 line before and after a match,
and adds three dashes to split the
sequences. Linenumbers for a match is
added.
Cgrep breaks the context if the next
line is a match by itself.
" >/dev/tty
exit 2
fi
nl -b a |/usr/bin/sed -n ’
1 {
/‘“$1”‘n/! h
/’“$1”’/ {
p
a
—\

	n
}

}
:op
1! {
/‘“$1”’/! {
h
n
}
/‘“$1”’/ {
x
/‘“$1”’/ {
g
p
}
/‘“$1”’/! {
p
g
p
}
n
/‘“$1”’/ {
i
—\

		b op
	}
	/'"$1"'/! {
	p
	a\

—\

	}
}

}
'[/code]

Some stuff I made from ideas acquired in this thread! :slight_smile:

Here is one little tool to wrap something into html, by piping stuff into it. (Its’ called html_wrap.)

#!/bin/bash echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' echo ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">' echo '<head>' echo ' <meta http-equiv="content-type" content="text/html; charset=utf-8" />' echo ' <title>Wrapper</title>' echo '</head>' echo '<body>' cat - echo '</body>' echo '</html>'
Below is a script that shows your shell scripts and the like with qlmanager (quicklook.). I have called it “g

#!/bin/bash if [ $# -ne 1 ] ; then echo "Usage: g file. shows a file probably script with quicklook." >/dev/tty exit 2 fi if [ ! -e $1 ] ; then echo "g: Can't find $1" >/dev/tty exit 1 fi a=$(basename $1) ( echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' echo ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">' echo '<head>' echo ' <meta http-equiv="content-type" content="text/html; charset=utf-8" />' echo ' <title>Wrapper</title>' echo '</head>' echo '<body>' echo '<pre><code>' cat $1 |sed -e 's/</\</g' -e 's/>/\>/g' echo '</code></pre>' echo '</body>' echo '</html>' ) >/tmp/$a.html qlmanage -px /tmp/$a.html 2>&1 >/dev/null &
You need to chmod u+x to use both of course, and store them somwhere in your bin.

The idea is of course to use “g” from a do shell script, so that you can look at the scripts from Finder. :slight_smile:

Edit

I have made a minor change, removing the path when generating the html file, so it works properly outside the folder it is placed. :slight_smile:

Here is a small applescript, that calls it with the first item of the current Finder selection as argument.

tell application "Finder"
    set a to its selection as alias list
    if a is not missing value then
        if ((count a) > 1) then
            set a to first item of a
            set a to POSIX path of a
        else
            set a to POSIX path of a
        end if
        do shell script "g " & quoted form of a & " 2>&1 >/dev/null  &"
    end if
end tell

By the way, I saved the applescript above as an applet, found an icon for it, and dragged it onto the toolbar, just great! :smiley:

Wow, everybody’s been busy! Yeah, nice poem. :smiley:

I tried to do this script with just the lower case commands for now. Finally got the loop in the right place. Had to hold the matching line in the buffer, incase the next line had a match also. Had to use insert (i) instead of append, because append only appends after all lines are printed within the curly braces.


set t to quoted form of "The again
rain
train
in
Spain
stays
mainly
in
the
brain
stain
plain."
set cmd to "echo " & t & " | sed -n '
/ain/ !{
x
d
}
/ain/ {
:loop
x
# print the line before
p
# get a copy of the matching lline
x
# print the matching line
p
# hold this lines in case next line contains pattern
h
# clear pattern space and get next line
n
# print next line
p
# branch if line contains pattern
# insert divider here
i\\
---
/ain/ b loop
x
}'"
do shell script cmd

This method is limited though, to one line before and after a match. I’ll have to learn Nigel’s method in the following sections with the capitalized commands for more veratillity.

McUsr,

How did you know I was planning on learning html? You must be a psychic. :slight_smile: Actually, I don’t really know what is going on in your scripts yet. I’ve been walking around in a daze, thinking about where to put the loop. Now I can reread the posts.

Editted: oops, posted the wrong script.


set t to quoted form of "The brain
rain
drain
in
Spain
stays
mainly
in
the
Staines
plain
again
Jane

again"
set cmd to "echo " & t & " | sed -n '
/ain/ !{
x
d
}
/ain/ {
:loop
x
# print the line before
p
# get a copy of the matching lline
g
# print the matching line
p
# clear pattern space and get next line
n
# print next line
p
# insert divider here
i\\
---
# branch if line contains pattern
/ain/ b loop
x
}'"
do shell script cmd

Thanks a lot everybody,
It’s been fun.

Hello kel. :slight_smile:

I’ll just tell you that the shell script works from an automator service as well, with a shell script action that looks like this:

g "$1"

Looks like you got it when it comes to emulate grep -C 1 , the final exercise would be to place hyphens and colons correctly, (I’m not up for that.) :slight_smile:

Hello.

I have added substitution of ‘<’ and ‘>’ to < respective > in the “g” shell-script in post #24 to make those turn up as they should, with any following/previous text in the formatted html.

Come to think about it, you can add your own font styles here, should you be dissatisfied with the size of the font quicklook gives for whatever file you want to read. You’ll loose the syntax coloring of course, I’m thinking of .c , .m and .h files here specificially.)

The pre/code style that are standard for html, works perfectly for me, I loose the syntax colouring, but what is the point of having syntax colouring, if you can’t read what is written? :slight_smile: