linkyndy
linkyndy

Reputation: 17900

Don't treat variable content as special characters in sed

I have the following sed command:

sed -i "4i\ $CHANGES" ./CHANGELOG.rst

However, my $CHANGES variable looks something like this:

title
-----

* list
  * elem
  * elem

Hence, the above command fails with the following error: sed: -e expression #1, char 149: unknown command: '*'. I understand that this happens because the contents of the $CHANGES variable are somewhat interpreted, but how do I specify to only use the string in the variable as a raw string, without interpreting its contents?

Upvotes: 2

Views: 281

Answers (4)

glenn jackman
glenn jackman

Reputation: 246764

Good old ed:

$ CHANGES="title
-----

* list
  * elem
  * elem"

$ seq 10 > file

$ ed file <<END
4i
$CHANGES
.
w
q
END
21
59

$ cat file
1
2
3
title
-----

* list
  * elem
  * elem
4
5
6
7
8
9
10

Upvotes: 1

mklement0
mklement0

Reputation: 437197

Try

sed -i "4 i\
${CHANGES//$'\n'/\\$'\n'}" ./CHANGELOG.rst

As @NeronLeVelu notes,

  • you need a newline after i\
  • newlines in text passed to sed's i function must be \-escaped - this is what the bash parameter (variable) substitution above does.

Upvotes: 2

NeronLeVelu
NeronLeVelu

Reputation: 10039

sed "4 i\
$CHANGES" ./CHANGELOG.rst
  • Need a new line after the i\
  • On some sed a space before the i
  • $Changes must have all new line escaped with \

so awk is better in this case. Another way is to use sed with a temporary file (i insert before and rappend file so 1 line before)

echo "${CHANGES}" > TempoFile
sed "3 r TempoFile" YourFile
rm TempoFile

Upvotes: 2

Tom Fenech
Tom Fenech

Reputation: 74595

Another good old "use AWK instead" style answer...

If you just want to insert that string on line 4, you could do so in AWK like this:

awk -v var="$CHANGES" 'NR == 4 { print var } { print }' ./CHANGELOG.rst > tmp && mv tmp ./CHANGELOG.rst

This would insert the contents of your variable $CHANGES before line 4 in your file.

As mentioned in the comments and elsewhere, newer versions of gawk (>= 4.1.0) can do in-place editing:

gawk -i inplace -v var="$CHANGES" 'NR == 4 { print var } { print }' ./CHANGELOG.rst

Saving you a few characters.

Upvotes: 2

Related Questions