2

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?

linkyndy
  • 17,038
  • 20
  • 114
  • 194
  • Where is the content of `$CHANGES` coming from? If it is a file, we can work from that with `sed ... r`. – fedorqui Mar 06 '14 at 14:31
  • No, it's a variable built in the same script, before I need to add its contents to the specified file. – linkyndy Mar 06 '14 at 14:35

4 Answers4

2

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.

Community
  • 1
  • 1
Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • As far as I'm aware, AWK doesn't support in-place editing. Funny you should mention it though, the typical answer to that question would be "use sed instead"! http://stackoverflow.com/questions/910121/in-place-editing-using-awk – Tom Fenech Mar 06 '14 at 14:52
  • It does... but just in new versions: http://stackoverflow.com/questions/16529716/awk-save-modifications-inplace – fedorqui Mar 06 '14 at 14:54
  • 1
    Even `sed -i` just hides the details of a temporary file; it still writes to one and renames it to the original behind the scenes. – chepner Mar 06 '14 at 14:57
2
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
NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43
2

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.
mklement0
  • 382,024
  • 64
  • 607
  • 775
1

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
glenn jackman
  • 238,783
  • 38
  • 220
  • 352