Re: [List] Re: Nice easy sed question

From: Bob Proulx <bob_at_proulx.com>
Date: Fri, 12 Sep 2025 22:19:12 UTC
Frank Leonhardt wrote:
> TLDR: The methods and syntax I was using are fine on GNU sed but
> BSD sed appears to require a newline and there's no way around it.

Since this is the FreeBSD questions mailing list I don't think I can
be faulted for assuming we are talking about FreeBSD sed by default.
And you specifically asked about BSD sed.  If you want to talk about
GNU sed then of course it's GNU and a different source code tree and
will have differences.

> And we all seem to agree that the documentation isn't the best.

It's really not that bad though.  And there are many examples
available on the web.  For an excellent treatment of sed I suggest the
O'Reilly book "sed & awk" by Dale Dougherty & Arnold Robbins.

> I was suspecting the newline was the issue. However the following do
> work perfectly correctly on GNU sed.

GNU sed is a different code base.  It has different features added to
it.  This is sometimes good and sometimes bad.  Differences create
portability problems.  But extensions are sometimes useful.  But
FreeBSD sed is a traditional Unix sed and expects a traditional syntax.

> sed  -i.bak  '/Line 2/a\New Line' example.txt
> sed  -i.bak  -e '/Line 2/a\' -e 'New Line' example.txt

Those are not GNU sed syntax either.

GNU sed has extended sed to allow single line append, insert, change
commands.  It's not portable.  But GNU sed allows this.

    GNU$ printf "%s\n" "Line 1" "Line 2" "Line 3" |
        sed -e '/^Line 2/iLine before 2' -e '/^Line 2/aLine after 2'

Outputs:

    Line 1
    Line before
    Line 2
    Line after
    Line 3

Note that the backslash after the a, i, c is not there when using the
GNU sed extension syntax.  But it must be there for portable sed for
use with the traditional Unix BSD sed.

    BSD$ printf "%s\n" "Line 1" "Line 2" "Line 3" |
    >     sed -e '/^Line 2/i\
    > Line before 2' -e '/^Line 2/a\
    > Line after 2'

Outputs:

    Line 1
    Line before 2
    Line 2
    Line after 2
    Line 3

Using the traditional syntax one can list multiple commands together.

    $ printf "%s\n" "Line 1" "Line 2" "Line 3" | sed -e '
    /^Line 2/i\
    Line before 2
    /^Line 2/a\
    Line after 2'

Outputs:

    Line 1
    Line before 2
    Line 2
    Line after 2
    Line 3

Notice that the insert and append commands are terminated by a
newline.  The newline, or end of input, is part of the syntax.

> I think I've finally found something that Linux does better - it took long
> enough :-)

:-)

GNU is a newer rewrite and there are various extensions there that BSD
could benefit from implementing as well.

> If BSD sed really is that particular about there being a newline, which IMHO
> is really clunky in a script, then that's what I'll have to do

Yes.  It needs a newline.  But you can insert that newline in more
ways than using an extra line there.

> - and put a wrapper around it so it doesn't offend my sensibilities!

I don't find the line break to be that terrible when used in a script.
It annoys me more on the command line.  But in a script it is fine.

Arthur's posting suggests using the shell's $'...' quoting which
enables escape sequences which enables embedding newlines.  That's a
reasonable option.  I'll make a follow-up comment there.

> Kyle Evans wrote:
> > The synopsis and usage string don't seem to be based in reality
> > all the way back to BSD 4.4 Lite, the original usage here is
> > technically fine.
...
> Yes, exactly! I've sanity checked things in Kernighan and Pike, which is a
> lot better than the man page but all their examples centre on the 's'
> command. Thanks, Frank.

I think the synopsis is about as good as it can get in the document
format of a manpage.  It is missing a little explanation that says how
to terminate a, i, c commands and how to chain in multiple commands
with one following the other.  It wasn't designed to squeeze an entire
sed program all on one line, at least not all of the time.  There are
some quite long and pretty gnarly multiline sed programs that are
unreadable on multiple lines without jamming them all together onto
one line.

Bob