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)