2

I have an XML file with the following structure:

    <root>
       <station name = "insert_text"/>
       <station name = "insert_text"/>
       <station name = "insert_text"/>
    </root>

I wanted to replace the text "insert_text" with the values from a text file which looks like:

    Station1
    Station2
    Station3

After reading the input file above, the generated XML file should look like:

    <root>
       <station name = "Station1"/>
       <station name = "Station2"/>
       <station name = "Station3"/>
    </root>

The script I now use is as follows and it replaces all the 3 lines only with 'Station1'.

    while read a
    do 
        sed -i -e "s/insert_text/$a/g" filename.xml
    done<inputfile.txt

What should I change in order to replace each of the lines in the XML file with different texts?

1

3 Answers 3

3

Problem

The issue with your code is that once it replaces insert_text in the file, there are no more insert_texts to be replaced by Station2 and Station3.

Solution

The solution is to quit the replacing once the first insert_text has be replaced, and read the next line from the file

You can do this by

while read a;     
do          
   sed  "1,/insert_text/ s/insert_text/$a/; " input;     
done < file

What it does?

  • 1,/insert_text/ This is an address range, tells the sed to do the replacing from the line 1 till the first insert_text. No other insert_texts are replaced

OR

sed  "/insert_text/{s/insert_text/$a/;q;}" input;
Sign up to request clarification or add additional context in comments.

7 Comments

Good approach, but I would implement this with sed "/insert_text/{s//$a/g; q;}"
@WilliamPursell Yeah, that should work in gnu-sed, I was testing in BSD sed and was not able to make it work.
P.S.: BSD Sed requires the last command in a block to be ;-terminated, unlike GNU Sed (... q; } vs. { ... q }). That's why @WilliamPursell's command works even with BSD Sed, but the one you quoted in your answer does not. Also note his omission of the regex in the s// call, which conveniently reuses the one that was used to match the line.
@mklement0 - I was just going to point that out; you beat me to it. Thanks for keeping the torch burning for us BSD users. ;-)
@mklement0 The ; was something that I missed :(. Thanks for the tip that s// will replace the already matched pattern. That was new for me
|
3

I think awk is better suited for this task:

Demo

$ cat inputfile.dat 
Station1
Station2
Station3
$ cat filename.xml 
   <root>
       <station name = "insert_text"/>
       <station name = "insert_text"/>
       <station name = "insert_text"/>
    </root>


$ awk 'NR==FNR{a[++c]=$1;next}/station name/{sub("insert_text",a[++i])}1' inputfile.dat filename.xml 
   <root>
       <station name = "Station1"/>
       <station name = "Station2"/>
       <station name = "Station3"/>
    </root>

Comments

1

Another awk take on this... Rather than reading one file into a an array in memory and then reading the second file for text to replace, you can stream through both files at once:

$ cat inp1
Station1
Station2
Station3
$ cat inp2
    <root>
       <station name = "insert_text"/>
       <station name = "insert_text"/>
       <station name = "insert_text"/>
    </root>
$ awk -vtext="insert_text" '$0~text{getline stn <"inp1"; sub(/insert_text/,stn)} 1' inp2
    <root>
       <station name = "Station1"/>
       <station name = "Station2"/>
       <station name = "Station3"/>
    </root>

This approach will be advantageous if your list of stations is larger than you can comfortably fit in memory.

Broken out for easier reading, here's what the script does:

$0 ~ text {                 # run these commands if we find your text
  getline stn <"inp1"       # read a new input line from the file "inp1"
  sub(/insert_text/,stn)    # do the substitution.
}
1                           # shorthand for "print the current line".

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.