1

I'm writing a bash script, and I need it to make changes to an XML file, replacing a bunch of different servlet-name items with "disabledController".

I know I can do this using sed, however there are 2 different lines that have the same string, but only one needs to be changed.

For example, I need to change this:

<servlet>
        <servlet-name>CreateCertificateAuthorityBackup</servlet-name>
        <servlet-class>com.company.ca.CABackup</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>CreateCertificateAuthorityBackup</servlet-name>
        <url-pattern>createCertificateAuthorityBackup</url-pattern>
    </servlet-mapping>

Into this:

<servlet>
        <servlet-name>CreateCertificateAuthorityBackup</servlet-name>
        <servlet-class>com.company.ca.CABackup</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>disabledControler</servlet-name>
        <url-pattern>createCertificateAuthorityBackup</url-pattern>
    </servlet-mapping>

If I use sed like so:

sed "s@<servlet-name>CreateCertificateAuthorityBackup.*@<servlet-name>disabledController</servlet-name>@"

It replaces both servlet-name items instead of just the 2nd one. Is there a way to do what I want to do here?

4

2 回答 2

1

要仅替换第二次出现,请使用从文件开头开始的嵌套和模式范围:

sed -i '0,/CreateCertificateAuthorityBackup/! { 0,//s//disabledController/ }' file

或全部:

sed -i '0,/CreateCertificateAuthorityBackup/! { 0,/CreateCertificateAuthorityBackup/s/CreateCertificateAuthorityBackup/disabledController/ }' file

普通命令的解释:

0,/CreateCertificateAuthorityBackup/      # is a pattern range from the start of
                                          # the file to the first occurrence of:
                                          # 'CreateCertificateAuthorityBackup'

! { ... }                                 # if not in the above pattern range, do
                                          # every between the braces.

0,/CreateCertificateAuthorityBackup/      # match between the beginning of the
                                          # file again and the next occurrence
                                          # of 'CreateCertificateAuthorityBackup'

s/ ... / ... /                            # perform the necessary substitution

如果您想替换第三次出现,只需添加另一层嵌套:

sed '0,/CreateCertificateAuthorityBackup/! { 0,//! { 0,// s//disabledController/ } }' file

编辑:

要在“servlet-mapping”标签之间进行更改,您只需要一个模式范围:

sed '/<servlet-mapping>/,/<\/servlet-mapping>/s/CreateCertificateAuthorityBackup/disabledController/' file

您可能想在此处阅读有关模式范围的更多信息。HTH。

于 2013-02-11T01:34:52.543 回答
0

使用 XML 工具修改 XML。与将其视为文本相比,这使得该解决方案更加健壮且符合标准。如果文件按照 XML 规则重新格式化,替换不会失败,如果其他 XML 标准工具对同一文件进行操作,替换也不会中断。

您可以使用xmlstarlet来替换servlet-mappingservlet-name值是CreateCertificateAuthorityBackup这样的:

xmlstarlet edit -L \
  -u '/web-app/servlet-mapping/servlet-name[normalize-space(text())="CreateCertificateAuthorityBackup"]' \
  -v "disabledController"  web.xml

给出web.xml这样的:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <servlet>
    <servlet-name>CreateCertificateAuthorityBackup</servlet-name>
    <servlet-class>com.company.ca.CABackup</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>CreateCertificateAuthorityBackup</servlet-name>
    <url-pattern>createCertificateAuthorityBackup</url-pattern>
  </servlet-mapping>
</web-app>
于 2013-02-11T02:19:13.230 回答