6

I am trying to add field at the end of tag using sed script. Suppose I have a tag in XML file:

<book name="Sed tutorial" price="250"/> 

Now I want to add field as Book_Width="A" after end of <book/> tag so that my tag becomes:

<book name="Sed tutorial" price="250" Book_Width="A"/> 

I tried with sed:

sed '/<book "[^>]*>/ a Book_Width="A"' 

but it gives:

<book name="Sed tutorial" price="250"/> Book_Width="A" 
1

5 Answers 5

19

You should not parse XML with sed; use an XML parser such as xmlstarlet instead. For your task it would be:

xmlstarlet ed -O --inplace --insert "/book" --type attr -n Book_Width -v A xml_file 

The file content is then:

<book name="Sed tutorial" price="250" Book_Width="A"/> 
  • The ed means edit mode to edit the XML tree.
  • -O omits the XML tag.
  • We want to insert something with --insert.
  • "/book" is the path where to insert.
  • --type attr: it's an attribute we want to insert.
  • The name -n of the attribute.
  • The value -v.
3
  • can I update xml_file rather printing its output
    – krishna
    CommentedAug 12, 2015 at 10:43
  • @krishna Yes with --inplace I added it to my answer
    – chaos
    CommentedAug 12, 2015 at 10:48
  • If Book_Width="A" already present in XML file then how can we skip that tag
    – krishna
    CommentedAug 13, 2015 at 10:30
5

in sed "a" appends a pattern IN A NEW LINE.

what you want to do is replace (substitute). Let's use a colon as separator for clarity:

sed 's:\(<book.*\)\(/>\):\1 Book_Width="A"\2:' 

anything in \( .. \) is a pattern memorized by the order of appearance and recalled by \indexnumber , e.g. \1 will reproduce the first pattern saved.

So we are memorizing <book name="Sed tutorial" price="250" as pattern 1 and /> as pattern 2 and just insert Book_Width="A" in the middle.

echo '<book name="Sed tutorial" price="250"/>' | sed 's:\(<book.*\)\(/>\):\1 Book_Width="A"\2:' <book name="Sed tutorial" price="250" Book_Width="A"/> 
    4

    Assuming that your XML file is literally just a single line with a book node, as shown in the question, you may add a Book_Width attribute to that book node using xq (part of yq from https://kislyuk.github.io/yq/) like so:

    $ xq -x '.book."@Book_Width" |= "A"' file.xml <book name="Sed tutorial" price="250" Book_Width="A"></book> 

    If you have data that you'd like to insert as the attribute's value:

    $ myvariable='20 cm' $ xq -x --arg val "$myvariable" '.book."@Book_Width" |= $val' file.xml <book name="Sed tutorial" price="250" Book_Width="20 cm"></book> 
      1

      With awk you can do something like this:

      Supposing the line is in file file1.xml then:

      awk -F '/' '{print $1,"Book_Width=\"A\"",FS,$2}' file1.xml 
      2
      • This is not checking that the tag is "book"CommentedAug 12, 2015 at 13:30
      • 1
        In general a solution using sed or awk is only going to work on a subset of XML; if it works on the subset of XML that you apply it to, then that's fine. Just be aware that it will break as soon as it gets unexpected input; and if you put it into production, then we will see a slew of StackOverflow questions from people who want to know how to generate your chosen (proprietary and probably undocumented) subset of XML. Don't laugh - it happens all the time.CommentedMay 10, 2019 at 8:11
      0

      The solution would be to use sed and not use any external packages or commands.

      echo '<book name="Sed tutorial" price="250"/>' | sed 's/<book /& Book_Width="A"/' 

      Output:

      <book Book_Width="A" name="Sed tutorial" price="250"/> 

      If you have a file.

      sed 's/<book /& Book_Width="A"/' ${FILE_NAME} 

      or if you want to replace inplace

      sed -i 's/<book /& Book_Width="A"/' ${FILE_NAME} 

      &: This symbol is a special character in sed that represents the entire matched string, i.e., <book(space). We use it here in the replacement pattern to include the original <book tag in the modified text.

      4
      • 1
        It is generaly a bad practiec to use awk/sed/perl to edit XML files. What would happen if there is a bookmark tag ?
        – Archemar
        CommentedApr 13, 2023 at 11:25
      • Best solution would be not to use sed but instead to use an XML-aware parserCommentedApr 24, 2023 at 16:29
      • How about when you have an environment where you are allowed to use any 3rd party software?CommentedApr 24, 2023 at 16:31
      • Don't accept a job if you are forced to do bad practice. Move on next inc that care modern and robust coding.CommentedApr 24, 2023 at 17:51

      You must log in to answer this question.

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.