使用具有特殊字符的占位符在两个占位符之间查找和替换XML文件中的文本

时间:2013-08-24 19:51:20

标签: sed

我有下面提到的要求。

示例file.txt ::

<?xml version='1.0' encoding='utf-8'?>
<Server port="${shutdown.port}" shutdown="SHUTDOWN">

<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

<Listener className="com.springsource.tcserver.serviceability.rmi.JmxSocketListener"
        port="${jmx.port}"
        bind="127.0.0.1"
        useSSL="false"
        passwordFile="${catalina.base}/conf/jmxremote.password"
        accessFile="${catalina.base}/conf/jmxremote.access"
        authenticate="true"/>

<Listener className="com.springsource.tcserver.serviceability.deploy.TcContainerDeployer" />

 <GlobalNamingResources>

 <Resource
       name="jdbc/myDBPool1"
       auth="Container"
       type="oracle.jdbc.pool.OracleDataSource"
       description="Oracle Datasource"
       factory="oracle.jdbc.pool.OracleDataSourceFactory"
       url="jdbc:oracle:thin:@localhost:<dbanme>"
       user="myusername"
       password="somepassword1"
       validationQuery="SELECT 1 FROM DUAL"
 />


 <Resource
       name="jdbc/myDBPool2"
       auth="Container"
       type="oracle.jdbc.pool.OracleDataSource"
       description="Oracle Datasource"
       factory="oracle.jdbc.pool.OracleDataSourceFactory"
       url="jdbc:oracle:thin:@localhost:<dbanme>"
       user="myusername"
       password="somepassword2"
       validationQuery="SELECT 1 FROM DUAL"
/>   

<Resource
           name="jdbc/myDBPool3"
           auth="Container"
           type="oracle.jdbc.pool.OracleDataSource"
           description="Oracle Datasource"
           factory="oracle.jdbc.pool.OracleDataSourceFactory"
           url="jdbc:oracle:thin:@localhost:<dbanme>"
           user="myusername"
           password="somepassword3"
           validationQuery="SELECT 1 FROM DUAL"
/>

 </GlobalNamingResources>

 <Service name="Catalina">

 <Executor name="tomcatThreadPool" namePrefix="tomcat-http--" maxThreads="300" minSpareThreads="50"/>

 <Connector executor="tomcatThreadPool"
           port="${http.port}"
           protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="${https.port}"
           acceptCount="100"
           maxKeepAliveRequests="15"/>

 <Engine name="Catalina" defaultHost="localhost">
 <!--
  <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
         resourceName="UserDatabase"/>
  -->
    <Host name="localhost"  appBase="webapps"
        unpackWARs="true" autoDeploy="true" deployOnStartup="true" deployXML="true"
        xmlValidation="false" xmlNamespaceAware="false">
   </Host>
  </Engine>
</Service>
</Server>

我正在尝试使用此脚本在两个字符串(包括字符串)之间找到一些文本(。密码。),然后用占位符替换它。每当我的cmdlinepasswd占位符有特殊字符时,说“/”字符就会失败。

sed -ie "/$datasource/,/password*/ {s/.*password.*/\tpassword=\"$cmdlinepasswd\"/;}"    file.txt

假设         数据源= JDBC / myDBPool1         cmdlinepasswd =新/ passwd的

我是脚本新手,任何帮助都将不胜感激。 谢谢。

2 个答案:

答案 0 :(得分:1)

这应该这样做:

awk -v RS= -v ORS='\n\n' -v datasource="jdbc/myDBPool1" -v cmdlinepasswd="new/passwd" '
$0 ~ "^[[:space:]]*<Resource.*name=\"" datasource "\"" {
    sub(/password="[^"]+"/,"password=\"" cmdlinepasswd "\"")
} 1' file

它只查找以<Resource后跟name="<your datasource variable value>"开头的记录,如果找到,则会替换该记录中的密码。

如果你已经有了shell变量

datasource="jdbc/myDBPool1"
cmdlinepasswd="new/passwd"

将它们传递给awk:

awk -v RS= -v ORS='\n\n' -v datasource="$datasource" -v cmdlinepasswd="$cmdlinepasswd" '
$0 ~ "^[[:space:]]*<Resource.*name=\"" datasource "\"" {
    sub(/password="[^"]+"/,"password=\"" cmdlinepasswd "\"")
} 1' file

答案 1 :(得分:0)

使用的一种方法。它接受三个参数,即检查/替换的变量和输入文件。它比更好,因为它对参数进行了引用(\Q),它可以逃避正则表达式的许多特殊字符。

perl -pe '
    ## Get arguments but input file.
    BEGIN { ($datasource,$cmdlinepasswd) = (shift,shift) }
    ## Get a range from resource name until the line with the password.
    if ( $range = ( m/=\s*"\Q${datasource}"/ ... /password\s*=/ ) ) {
        ## "E0" points to last line (that contains the password, so
        ## change it.
        if ( q|E0| eq substr $range, -2 ) {
            s/(=\s*").*("\s*)$/$1${cmdlinepasswd}$2/;
        }
    }
' "$datasource" "$cmdlinepasswd" infile

使用您的示例输入数据,它会产生(仅显示已修改的密码部分,其余部分保持不变):

<?xml version='1.0' encoding='utf-8'?>
<Server port="${shutdown.port}" shutdown="SHUTDOWN">

<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

<Listener className="com.springsource.tcserver.serviceability.rmi.JmxSocketListener"
        port="${jmx.port}"
        bind="127.0.0.1"
        useSSL="false"
        passwordFile="${catalina.base}/conf/jmxremote.password"
        accessFile="${catalina.base}/conf/jmxremote.access"
        authenticate="true"/>

<Listener className="com.springsource.tcserver.serviceability.deploy.TcContainerDeployer" />

 <GlobalNamingResources>

 <Resource
       name="jdbc/myDBPool1"
       auth="Container"
       type="oracle.jdbc.pool.OracleDataSource"
       description="Oracle Datasource"
       factory="oracle.jdbc.pool.OracleDataSourceFactory"
       url="jdbc:oracle:thin:@localhost:<dbanme>"
       user="myusername"
       password="new/passwd"
       validationQuery="SELECT 1 FROM DUAL"
 />

...

注意:看到您的编辑后,使用xml解析器是更好的选择,但此解决方案似乎适用于我的测试。