From: arnej@alkymi.unit.no (Arne Henrik Juul)
Newsgroups: comp.unix.questions,comp.unix.shell
Subject: Re: Need help understanding sed
Date: 23 Jan 93 01:57:25
Organization: Norwegian Institute of Technology
NNTP-Posting-Host: ild.alkymi.unit.no
In-reply-to: mich@lin.infolog.se's message of Fri, 22 Jan 1993 21:08:55 GMT

In article <1993Jan22.210855.29212@infolog.se>
 mich@lin.infolog.se (Thomas Michanek) writes:

 > From: mich@lin.infolog.se (Thomas Michanek)

 > I've started to use 'sed' a lot, not only for simple 's/.../.../'
 > substitutions, but I have trouble understanding the man page for sed
 > when trying to using more complex commands. Could someone help me
 > with the following issues:

I'll try to help you a bit, but you also need to read the man page
more intensely. Some things are best explained by example, though.

 > 1. The man page sais:

	Some commands use a hold space to save all or  part  of  the
	pattern space for subsequent retrieval.

 >    However, I can't find _which_ commands do that and how. I've tried
 >    using the g, G, h, H, x commands, but sed produces no output.

well, let's look at 'g' and 'h': g copies hold space into pattern
space, h is vice versa. So
   $ sed '/a/h;/b/g'
Will `remember' lines containing the letter "a", and replace lines
containing "b" with the last such `remembered' line.

input			output		comment
groo			groo		
b line					hold space initially empty
foo			foo
alf			alf		remember this
blue			alf		and copy it in
glue			glue
blue too		alf		and copy it in again
new a line		new a line	remember
newer a line		newer a line	remember
b line			newer a line	copy hold space in
both a and b		both a and b	remember, then copy


 > 2. "\n" in a context address is supposed to match a NEWLINE in the
 >    pattern space. But doesn't sed read one line at a time into the
 >    pattern space, each line separated by NEWLINE?

Yes, you can't use this without using N, which does:
    (2)N        Append the next line of  input  to  the  pattern
                space  with  an  embedded newline.  (The current
                line number changes.)


 >    I want to look for files containing the pattern "A" in one line
 >    and the pattern "B" in the next line. The following doesn't work:
 >
 >	sed '/A\nB/p'
 >
 >    How can you do such a 'multi-line grep'?

   $ sed -n 'N;/A.*\n.*B/p'
will take two and two lines, and check if they together contain the regexp.
So with input
 hey
 you
 blArg
 foo-BAR
 and
 Alpha
 Beta
 too!
it will 'grep' out just
 blArg
 foo-Bar
not the 'Alpha Beta' two-liner because of odd-even considerations. However
   $ sed -n 'N;/A.*\n.*B/p;D'
will find both, because it doesn't discard *all* of pattern space, just
the first of the two lines we have got. The normal cycle is:
     In normal operation sed cyclically copies a  line  of  input
     into a pattern space (unless there is something left after a
     D command), sequentially applies all commands with addresses
     matching  that  pattern  space until reaching the end of the
     script, copies the pattern  space  to  the  standard  output
     (except under -n), and finally, deletes the pattern space.
It's all in the man page, but it isn't easy :-)

 > 3. What's the difference between the commands n and p? The man page sais 
 >    n copies the pattern space to stdout, but it has never worked for me.

with the -n option, it will *not* copy the pattern space to stdout.
I think this is just a bug in the man page. But consider
   $ sed '/^ok:/n;s/^/ok:/'
which adds "ok:" to all lines which does not already have it.

 > 4. What's the syntax for the { } command grouping? No matter how I try
 >    I get "Extra text at end of command" or "Unrecognized command".
 >
 >    Isn't sed '/A/{=;p}' supposed to print the line number and the pattern
 >    on stdout? I've tried quoting, backslashing, spaces, no semicolon etc.

It's a bit more baroque than that. '{' is actually a *command*, and you
would write in a sed script
/A/{
=
p
}

or in bourne/korn/etc. shell
   $ sed -n '/A/{
     =
     p
     }'

But you can say
   $ sed -n '/A/{;=;p;}'
which probably does what you want.

 > BTW, I'm using C shell on SunOS4.1.1 and "sed0.c 1.15 89/03/28 SMI".

For some things, like commands with embedded newlines, bourne-derived
shells are much better (for interactive use) than c shell. I personally
use and recommend GNU's Bourne Again SHell, or at least you should get
tcsh.

All of my examples above were tested with GNU sed 1.13, some also with
Sun's /usr/bin/sed, but they should work on most sed variants.

 > Your aid is urgent and welcome!!!

Hope this post aided you (and maybe others). I take no responsibility
for typos :-)

--
Arne H. Juul  --  arnej@lise.unit.no  -- University of Trondheim, Norway