修改XML文件中的字符串,而不更改相同的字符串

时间:2013-02-11 01:22:04

标签: bash sed

我正在编写一个bash脚本,我需要它来更改XML文件,用“disabledController”替换一堆不同的servlet-name项。

我知道我可以使用sed执行此操作,但是有两个不同的行具有相同的字符串,但只需要更改一个。

例如,我需要改变这个:

<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>

进入这个:

<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>

如果我像这样使用sed:

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

它取代了两个servlet-name项而不是第二个。有办法做我想做的事吗?

2 个答案:

答案 0 :(得分:1)

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

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

或完整:

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

longhand命令的说明:

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

您可能希望详细了解模式范围here。 HTH。

答案 1 :(得分:0)

使用XML工具修改XML。这使得该解决方案比将其视为文本更加健壮且符合标准。如果根据XML规则重新格式化文件,则替换不会失败,并且如果其他XML标准工具在同一文件上运行,则不会中断。

您可以使用xmlstarlet替换servlet-mapping值为servlet-name的{​​{1}},如下所示:

CreateCertificateAuthorityBackup

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

web.xml