Extra Backslash Required in First Appended Newline in sed

While appending some text after a matched pattern, I wanted to add an empty line with a comment to isolate my additions from the rest. However, I have noticed that for the very first n, I need to escape the with an additional (makes it \n) but this is apparently not required for rest of the appended text. Why is this so?

An example that I produced on a SUSE 11 server (bash v3.2.57(2) and GNU sed version 4.1.5) is:

<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="096c6d7e6d6c7f49616d796c6d6e6c38">[email protected]</a>:/edw> sed '/test/a \nNot a testnJust Playing' <<< test
test

Not a test
Just Playing

If I do not escape the first n (right after the a sed command, I get an n printed instead of a newline.

<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9efbfae9fafbe8def6faeefbfaf9fbaf">[email protected]</a>:/edw> sed '/test/a nNot a testnJust Playing' <<< test
test
nNot a test
Just Playing

Notice that I have intentionally added a space after a command so that it doesn’t conflict accidentally with alternate syntax.

Same behavior is observed if I replace n with t.Number of spaces after a command do not seem to matter; the first backslash needs to be escaped to print the special character even after multiple spaces.


Same is the case on another environment, where I originally observed this; a Centos 7 x64 VM, bash version is 4.2.46(2) and sed version is GNU sed 4.2.2

sed -i '/[mysqld]/a \n# <<INSERTED MANUALLY>>ntransaction-isolation=READ-COMMITTEDninnodb_flush_method=O_DIRECTnmax_connections=550n# <<END OF MANUAL INSERTIONS >>n' /etc/my.cnf

Output:

...
[mysqld]

# <<INSERTED MANUALLY>>
transaction-isolation=READ-COMMITTED
innodb_flush_method=O_DIRECT
max_connections=550
# <<END OF MANUAL INSERTIONS >>

...

Output Without Escaping first n:

[mysqld]
n# <<INSERTED MANUALLY>>
transaction-isolation=READ-COMMITTED
innodb_flush_method=O_DIRECT
max_connections=550
# <<END OF MANUAL INSERTIONS >>

Is there any particular reason for this behavior? I am unable to find any details while skimming through the docs (here), through, admittedly, I haven’t read the entire documentation thoroughly.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

The standard form of the a command in sed is

a
text to be appended

The c and i command follow the same format.

If further lines are to be appended, the newline of each has to be escaped:

a
text to
be appended

Standard sed does not know to interpret n as newline as GNU sed does, so your single line command with a non-GNU sed would be written (in bash) as

sed $'/test/a\n\nNot a test\nJust Playingn' <<<test

Here, we use $'...' to make the shell replace each n with an actual newline and \ with .

The command could be written as the following without the $'...' feature of bash:

sed '/test/a

Not a test
Just Playing
' <<<test

Both of these commands would work with GNU sed too.

GNU sed additionally allows the appended text to occur without an intervening newline between it and the preceding a, and allows for dropping the completely, but will interpret the immediately following the a command as the backslash in the standard a form of the command (this is the basic issue in your question). GNU sed also adds a newline at the end of the appended text in the script. So with GNU sed, you could write

sed '/test/a 
Not a test
Just Playing' <<<test

or, using the fact that GNU sed knows n,

sed '/test/a\nNot a testnJust Playing' <<<test

Method 2

It’s not exactly documented behaviour, but then the entire thing is an extension. All three commands that were extended similarly (a, i and c) behave the same way: leading whitespace is ignored, and if the text begins with , then it is discarded. Essentially, it doesn’t matter to sed which of these forms are used:

i foo
i foo
i 
foo

They’re all identical. (I know I used i here, but check the the descriptions of a, i and c – it’s surreal.)

And the code shows as much:

1111         case 'a':
1112         case 'i':
1113         case 'c':
1114           ch = in_nonblank ();
1115 
1116         read_text_to_slash:
1117           if (ch == EOF)
1118             bad_prog (_(EXPECTED_SLASH));
1119 
1120           if (ch == '\')
1121             ch = inchar ();


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x