Unable to add lines before a matching line if the content has new lines and this content is generated by a function
another alternative that looked good (Insert multiple lines into a file after specified pattern using shell script) but it only appends "AFTER". I need "BEFORE"
put the xml content into add.txt then
sed '/4/r add.txt' $FILE
#/bin/sh
FILE=/tmp/sample.txt
form_xml_string()
{
echo "<number value=\"11942\">"
echo " <string-attribute>\"hello\"</string-attribute>"
echo "</number>"
}
create_file()
{
if [ -e $FILE ]
then
echo "Removing file $FILE"
rm $FILE
fi
i=1
while [ $i -le 5 ]
do
echo "$i" >> $FILE
i=$(( i+1 ))
done
}
create_file
cat $FILE
# file sample.txt has numbers 1 to 5 in each line
# Now append the content from form_xml_string to line before 4
# command I tried
CONTENT=`form_xml_string`
echo "CONTENT is $CONTENT"
sed -i "/4/i $CONTENT" $FILE
cat $FILE
Expected output:
1
2
3
<number value="11942">
<string-attribute>"hello"</string-attribute>
</number>
4
5
Actual output (or error): sed: -e expression #1, char 31: unknown command: `<'
It's normal that you get that error, the syntax of your text is not compatibale with your sed command, allow me to elaborate:
First, you have a lot of /
s in your text, and /
is the delimiter insed
, that confuses the command, which is why you get that error. So you should escape all /
in the text you are using, by replacing them with \\/
(The extra \
is going to be interpreted by the shell).
Second, in the man for sed
, we can see this small line about /i
:
Insert text, which has each embedded newline preceded by a backslash
This means that you also need to add a \
before every newline, in your example this means adding \\
at the end of every echo
.
Edit:
Thanks to Toby Speight's comment, I noticed that I forgot completly about the possiblity of changing sed
's delimiter, which can make your life a lot easier, since you wouldn't have to add \\
before every /
in your text. To do this all you need is to change this line sed -i "/4/i $CONTENT" $FILE
to, for example, this sed -i "\\_4_i $CONTENT" $FILE
.
Here's how your script will become once you introduce these changes:
#! /bin/sh
FILE=/tmp/sample.txt
form_xml_string()
{
echo "<number value=\"11942\">\\"
echo " <string-attribute>\"hello\"</string-attribute>\\"
echo "</number>"
}
create_file()
{
if [ -e $FILE ]
then
echo "Removing file $FILE"
rm $FILE
fi
i=1
while [ $i -le 5 ]
do
echo "$i" >> $FILE
i=$(( i+1 ))
done
}
create_file
cat $FILE
# file sample.txt has numbers 1 to 5 in each line
# Now append the content from form_xml_string to line before 4
# command I tried
CONTENT=`form_xml_string`
echo "CONTENT is $CONTENT"
sed -i "\\_4_i $CONTENT" $FILE
cat $FILE