I'm trying to replace a block of text from file_to_change.xml with the entire content of changes.xml, which is a tag of the main file with a minor change.
This is the content of file_to_change.xml:
<clients>
<client>
<name>Bob</name>
<age>18</age>
</client>
<client>
<name>Alice</name>
<age>12</age>
</client>
<client>
<name>Carlos</name>
<age>28</age>
</client>
</clients>
And this is the content of changes.xml:
<client>
<name>Carlita</name>
<age>17</age>
</client>
And this is the content of an auxiliary file that contains the line i want to change:
<client>
<name>Carlos</name>
<age>28</age>
</client>
The great difference between the solution i'm looking for from the one explained here is that the files are not entirely equal. It is also important to say that the environment i'm working at do not allow me to use external tools, and for that reason i'm trying to find a "core" solution, using sed, awk, etc.
This is the command i was trying to use:
sed -i -e '1r changes.xml' -e '1,/r aux.xml/d' file_to_change.xml
I'm expecting that the file_to_change.xml look like this:
<clients>
<client>
<name>Bob</name>
<age>18</age>
</client>
<client>
<name>Alice</name>
<age>12</age>
</client>
<client>
<name>Carlita</name>
<age>17</age>
</client>
</clients>
CodePudding user response:
Using pure bash?
#!/bin/bash
file=$( < file_to_change.xml )
search=$( < aux.xml )
replacement=$( < changes.xml )
printf '%s\n' "${file/"$search"/$replacement}"
<clients>
<client>
<name>Bob</name>
<age>18</age>
</client>
<client>
<name>Alice</name>
<age>12</age>
</client>
<client>
<name>Carlita</name>
<age>17</age>
</client>
</clients>
CodePudding user response:
I would harness GNU AWK for this task following way, let file.txt content be
ABC
DEF
GHI
JKL
MNO
and file_detect.txt be
GHI
JKL
and file_replacement.txt be
123
456
789
then
awk 'BEGIN{RS=""}FILENAME=="file_replacement.txt"{repl=$0;next}FILENAME=="file_detect.txt"{find=$0;next}{place=index($0,find);print substr($0,1,place-1) repl substr($0,place length(find))}' file_replacement.txt file_detect.txt file.txt
gives output
ABC
DEF
123
456
789
MNO
Disclaimer: this solution assumes you have never blank lines in any of your files, if this does not hold change RS to any value which does not exist in any of files involved.
Explanation: firstly I inform GNU AWK that blank lines are to be considered row separators using RS set to empty string, aim there is to make GNU AWK consider whole file as big single line. Then when I encounter file named file_replacement.txt I simply store its' content into variable named repl and instruct GNU AWK to go to next line, so no other action is undertaken, similarly content of file_detect.txt are stored in variable named find. Then I use String functions following way, first index to detect where part to be replace is located, then I use substr to get part before part to be replaced substr($0,1,place-1) and part after part to be replaced substr($0,place length(find) and then print them concatenated using repl.
Warning: this solution assumes there is exactly one file_detect.txt inside file.txt.
(tested in GNU Awk 5.0.1)
