2013-02-11 70 views
1

我在寫一個bash腳本,我需要它對XML文件進行更改,用「disabledController」替換一堆不同的servlet名稱項目。修改XML文件中的字符串,但不更改相同的字符串

我知道我可以使用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 "[email protected]<servlet-name>CreateCertificateAuthorityBackup.*@<servlet-name>disabledController</servlet-name>@" 

它取代了servlet的名字物品而不是第二個。有沒有辦法做我想在這裏做的事情?

+2

我認爲xmlstarlet有一個選項可以做到這一點 – BeniBela 2013-02-11 01:23:45

回答

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映射」標籤之間的變化,你需要的是一個單一的模式範圍:

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

你可能喜歡的圖案範圍here閱讀更多。 HTH。

+0

燦你在這裏詳細闡述了實際發生的事情? 此外,有時需要改變的不是第二個。這可能是罕見情況下的第一或第三。 – jkitzmiller 2013-02-11 01:39:10

+0

@jkitzmiller:你確實說過你想替換'僅僅是第二'的事件。你如何定義要改變的事件?會說你想替換_last_事件是否準確? – Steve 2013-02-11 01:42:43

+0

夠公平的,我確實這麼說。我認爲描述它的最準確的方式是我想改變servlet-mapping標籤內的出現。 – jkitzmiller 2013-02-11 01:57:33

0

使用XML工具修改XML。這使得該解決方案比將其視爲文本更加健壯和符合標準。如果文件根據XML規則重新格式化,則替換不會失敗,並且如果其他XML標準工具在同一文件上操作則不會中斷。

您可以使用xmlstarlet更換servlet-mappingservlet-nameCreateCertificateAuthorityBackup這樣的:

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>