0

I have a file uca.xml (Thunar configuration for custom actions):

<?xml encoding="UTF-8" version="1.0"?>
<actions>
<action>
    <!--some code-->
</action>
</actions>
<--blank line here-->

Mind that the file ends with a blank line

I want a bash command/script to insert a file customAction.txt containing:

<action>
    <!--custom configuration-->
</action>

so it will end looking like:

<?xml encoding="UTF-8" version="1.0"?>
<actions>
<action>
    <!--some code-->
</action>
<action>
    <!--custom configuration-->
</action>
</actions>

I tried a method given by jfgagne:

sed -n -i -e '/<\/actions>/r customAction.txt' -e 1x -e '2,${x;p}' -e '${x;p}' uca.xml

but it works only if there is at least one character (not a blank line) inserted below the tag.

My temporary workaround is a script:

echo "someDummyText" >> uca.xml
sed -n -i -e '/<\/actions>/r customaction.txt' -e 1x -e '2,${x;p}' -e '${x;p}' uca.xml
sed -i 's/someDummyText//' uca.xml
sed -i '${/^$/d;}' uca.xml

but I believe there is a more elegant, one-line solution with sed. Thanks in advance.

Note: this is my very post to the U&L and StackExchange community, so please be lenient with me and do not hesitate to correct me verbosely if I did something wrong. I read the SE FAQ and tried to search for an answer elsewhere with not much luck.

mDfRg
  • 3
  • If you read all the answers there you will find that you could easily do that via awk/perl/ed. Why do you insist on using sed ? – don_crissti Mar 31 '16 at 14:02

2 Answers2

0

I think your solution is perfectly adequate. You can optimise it a bit by replacing the last 2 seds with just one:

sed -i '$d' uca.xml

After all, you just put the extra line there, so you know what you are removing.


If you are looking for alternative solutions, you can use sed to get the line number of the pattern match, and then use that -1 to do the read:

if lno=$(sed -n -e '/<\/actions>/=' uca.xml)
then let lno=lno-1
     sed  -i -e "$lno"'r customaction.txt' uca.xml
fi

or if you like the ancient but serviceable ed command you can do

ed -s uca.xml <<\!
?</actions>
-1r customaction.txt
w
q
!
meuh
  • 51,383
0

Using the sed read (r) command:

$ sed '\#</action>#r customAction.txt' uca.txt
<?xml encoding="UTF-8" version="1.0"?>
<actions>
<action>
    <!--some code-->
</action>
<action>
    <!--custom configuration-->
</action>
</actions>

There's a blank line at the end of the input file, and this is preserved in the output. The r command will insert the contents of the given file after finding the given pattern. This works as expected on the example data because the single occurrence of the string </action>. If there were more pre-existing actions in the input file, this would not work as expected.

The following would work on a file containing multiple actions:

gsed -e '\#</actions>#d' -e '$ r customAction.txt' -e '$ a\</actions>' uca.txt

It removes the </actions> tag when found and inserts the contents of customAction.txt at the end. Then it appends </actions> after that.

This way of writing the a command requires GNU sed (hence gsed).

Kusalananda
  • 333,661