Re: [List] Re: Nice easy sed question

From: Frank Leonhardt <freebsd-doc_at_fjl.co.uk>
Date: Fri, 12 Sep 2025 09:58:42 UTC
This is a reply to several including Bob, Sad and Kyle.

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. And
we all seem to agree that the documentation isn't the best.


On 12/09/2025 07:04, Bob Proulx wrote:

> Frank Leonhardt wrote:
>> I've got a file called example.txt:
>>
>> Line 1
>> Line 2
>> Line 3
>>
>> I'm trying to add "New Line" after "Line 2"
> Okay.
>
>> Both of these should work as far as I know:
>>
>> sed  -i.bak  '/Line 2/a\New Line' example.txt
> That \N is not valid syntax.
>
>> sed  -i.bak  -e '/Line 2/a\" -e "New Line' example.txt
> That \" is not valid syntax.
>
>> (BSD requires a backup specification for -i IIRC, or '')
> Yes.  An annoying choice!  Perl pioneered the syntax and being first
> at doing so and it being adequate everyone else should have followed
> for consistency.
>
>> If I run it with the -i and have a genuine newline after \ it does write the
>> correct stuff to stdout:
>>
>> # sed  '/Line 2/a\
>>> New Line' example.txt
>> Line 1
>> Line 2
>> New Line
>> Line 3
> Yes.  The \ must be followed by a newline.  You have the correct syntax.
>
>> With an -i in any variations of the first two (single command or two -e -e)
>> I just get errors like:
>>
>> ": invalid command code e
>> ": extra characters at the end of N command
>> ": extra characters after \ at the end of a command
>>
>> (All starting with " - why?)
> Works for me.  Here is an example.
>
>      rwp@mayhem:~$ sed -i.bak '/Line 2/a\
>      New Line' foo1
>      rwp@mayhem:~$ cat foo1
>      Line 1
>      Line 2
>      New Line
>      Line 3
>
> And with use of -e for two different expressions works too.
>
>      rwp@mayhem:~$ sed -i.bak -e '/^Line 2/a\
>      New Line' -e 's/3/4/' foo1
>      rwp@mayhem:~$ cat foo1
>      Line 1
>      Line 2
>      New Line
>      Line 4
>
> What is the exact command you are having trouble with?
>
>> The only way I can make it work is with -i.bak and on two lines (as above).
> The newline after the \ backslash is required.  That is the correct syntax.
>
>> The Fine Manual says of 'a':
>>
>>    [1addr]a\
>>       text    Write text to standard output immediately before each attempt to
>>               read a line of input, whether by executing the “N” function or by
>>               beginning a new cycle.
> The manual was written by people who already knew how it worked.  The
> newline after the backslash is as far as I know always required.  The
> behavior is based upon the ed feature.
>
>      man ed
>       (.)a    Append text to the buffer after the addressed line.  Text is
>               entered in input mode.  The current address is set to last line
>               entered.
>
> Here is an ed example.
>
>      rwp@mayhem:~$ ed -s foo1 <<EOF
>      /^Line 2/a
>      New line
>      .
>      w
>      q
>      EOF
>      rwp@mayhem:~$ cat foo1
>      Line 1
>      Line 2
>      New line
>      Line 3
>
>> This implies the newline is required but I'm struggling with finding a sane
>> syntax here. A pointer to some better documentation would be welcome!
> This confuses me because you have a working example using sed and it works.
>
>> Or is there a better utility for editing (non-system) configuration files by
>> script I just don't know about?
> That depends upon many things.  What file is being edited?  Is it an
> INI file?  A CSV?  Would a tool like Puppet, Chef, Salt, Ansible be
> better?  Perl is powerful and a good general purpose batch editing
> choice.  Perhaps ed is the best answer.  Any recommendation without
> information would just be a guess in the dark.
>
> I personally like sed and most often use sed to automate edit files.
> I always use it in combination with grep to look to see if the file
> needs to be edited first in order to make the sequence idempotent such
> that files are not always being touched if there is no reason to touch
> them.  Because having files updated all of the time falsely points
> fingers at them when there are problems.
>
> Bob

Thanks Bob, et al.

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

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

(I used mismatched quotes in the email when typingoriginally, but the correct way around on the command line).

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

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 - 
and put a wrapper around it so it doesn't offend my sensibilities! @ Sad 
Clouds Yes, awk. I've been meaning to make friends with awk since System 
V. I've just found other ways of doing things in the mean time.

On 12/09/2025 01:19, 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.
>
> Thanks,
>
> Kyle Evans

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.