[comp.unix.questions] how can I join a range of lines in sed?

psrc@mtunq.att.com (Paul S. R. Chisholm) (03/08/91)

I have a file with sections inside BEGIN/END pairs.  (In 99% of the
interesting cases, there are only either one or two lines between the
two dot lines, if that makes any difference.)  I want to "join" (in the
sense of the ed/ex/vi command) the lines together, and delete the
sentinal lines.  I could do this easily enough in awk, but the rest of
the job is done in a sed script, and I'd like to keep all the work
together if I can.

Somehow, I need to use the sed N command to "append the next line of
input to the pattern space with an embedded newline."  Without the N,
the pattern space consists of only one line at a time.  I've tried
substitutions and the t command (yuchh, I haven't used an if/goto
statement in over a decade!), but it never quite worked; e.g, this:
 
/^BEGIN/,/^END/{
	:loop
	N
	s/\nEND$//
	t done
	b loop
	:done
	s/^BEGIN\n//
	s/\n/ /g
	s/.*/.FOO "&"/
	p
	d
}

(the "p" and "d" are an attempt to flush the pattern space) run on the
following input:

Now
is
the
time
BEGIN
for
all
good
men
END
to
come
to
the
aid
BEGIN
of
their
country.
END

produced this:

Now
is
the
time
.FOO "for all good men"
.FOO "to come"
.FOO "to the"
.FOO "aid BEGIN"
.FOO "of their"
.FOO "country."

instead of this:

Now
is
the
time
.FOO "for all good men"
to
come
to
the
aid
.FOO "of their country."

Well, it worked through the first pair, but it doesn't seem to stop
right.

Any thoughts?  (I'll post a summary of e-mail responses, eventually,
but I'm notoriously slow.  I *will* read postings to this group.
Posting *and* mailing an answer would be greatly appreciated!)

Paul S. R. Chisholm, AT&T Bell Laboratories
att!mtunq!psrc, psrc@mtunq.att.com, AT&T Mail !psrchisholm
I'm not speaking for the company, I'm just speaking my mind.

tchrist@convex.COM (Tom Christiansen) (03/08/91)

From the keyboard of psrc@mtunq.att.com (Paul S. R. Chisholm):
:I have a file with sections inside BEGIN/END pairs.  (In 99% of the
:interesting cases, there are only either one or two lines between the
:two dot lines, if that makes any difference.)  I want to "join" (in the
:sense of the ed/ex/vi command) the lines together, and delete the
:sentinel lines.  I could do this easily enough in awk, but the rest of
:the job is done in a sed script, and I'd like to keep all the work
:together if I can.

I find it more difficult than it should be in sed to do relatively 
simple things.  Awk's more traditional control structures seems
to be easier on my brain.  

:Somehow, I need to use the sed N command to "append the next line of
:input to the pattern space with an embedded newline."  Without the N,
:the pattern space consists of only one line at a time.  I've tried
:substitutions and the t command (yuchh, I haven't used an if/goto
:statement in over a decade!), but it never quite worked; e.g, this:

You might consider running your whole script through s2p, the sed-to-perl
translator.  This would yield you the more traditional control structures
instead of sed's gotos and other oddities.  For the part that you posted,
this works:

    #!/usr/bin/perl -n
    if (/^BEGIN/ .. /^END/)  {
	if (/^BEGIN/) {
	    $hold = '';
	} elsif (/^END/) {
	    $hold =~ s/\n/ /g;
	    $hold =~ s/ $//;
	    print ".FOO \"$hold\"\n";
	} else {
	    $hold .= $_;
	}
    } else {
	print;
    } 

I just find this kind of thing easier to read than cryptic sed scripts.

--tom