Home > database >  sed to replace block of XML with another block (preserving new line breaks)
sed to replace block of XML with another block (preserving new line breaks)

Time:09-26

I have a XML file, that I'm trying to edit inplace using sed on a mac

Sample XML:

...
<clientSSLCertificatesConfiguration>
   <certificates>
      <clientCertificate>
        <certificate>
          <name>1234567</name>
          <storeAlias>cert_alias</storeAlias>
        </certificate>
      </clientCertificate>
    </certificates>
</clientSSLCertificatesConfiguration>
...

I'm trying to replace everything between <certificates> .. </certificates> using sed.

My replacement block is stored in a variable called $CERT_UPDATE looks like this:

<certificates>
    <clientCertificate>
     <certificate>
      <name>new_cert_name</name>
      <storeAlias>new_alias</storeAlias>
     </certificate>
    </clientCertificate>
</certificates>

So far, I've the following piece

sed -i -ne "/<certificates>/,/<\/certificates>/ {
    /<\/certificates>/ s@.*@$CERT_UPDATE@
    t
    d
}" my_file.xml

There are some issues in my script:

(1) The new line are not preserved in the file after replacement

(2) Rerunning the script deletes everything after </certificates>

(3) Running on online GNU sed tool works without error. However, running this on a mac I get sed: 2: "/<certificates>/,/<\/ce ...": unescaped newline inside substitute pattern error

CodePudding user response:

You can try this approach if your shell supports process substitution:

sed -i.backup -n '
/^[[:blank:]]*<certificates>/,/^[[:blank:]]*<\/certificates>/!{p;d;}
/^[[:blank:]]*<\/certificates>/!d
r '<(echo "$CERT_UPDATE") my_file.xml

Otherwise, you can write the contents of the variable CERT_UPDATE to a temporary file and replace the <(echo "$CERT_UPDATE") with the name of that temporary file.

CodePudding user response:

To modify the 2 fields with a dedicated XML tool such as you can say,

test "${bettersorrythansafe}" || cp file.xml file.xml.was
xmlstarlet edit --inplace --omit-decl \
  --var T '//clientCertificate/certificate[name = "1234567"]' \
  -u '$T/name' -v 'new_cert_name' \
  -u '$T/storeAlias' -v 'new_alias' \
file.xml

... assuming namespaces agree.

  • Related