Sed 查找XML文件中两个占位符之间的文本,并将其替换为具有特殊字符的占位符

Sed 查找XML文件中两个占位符之间的文本,并将其替换为具有特殊字符的占位符,sed,perl,Sed,Perl,我有一个下面提到的要求 示例文件.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.Jr

我有一个下面提到的要求

示例文件.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>
假定 datasource=jdbc/myDBPool1 cmdlinepasswd=new/passwd

我是新的脚本和任何帮助将不胜感激。 谢谢。

单向使用。它接受三个参数:要检查/替换的变量和输入文件。这比使用quotemeta(
\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
解析器将是一个更好的选择,但在我的测试中,此解决方案似乎有效。

单向使用。它接受三个参数:要检查/替换的变量和输入文件。这比使用quotemeta(
\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
解析器将是一个更好的选择,但此解决方案在我的测试中似乎有效。

这应该可以做到:

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
只需将它们作为以下内容传递到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
awk-v RS=-v ORS='\n\n'-v datasource=“$datasource”-v cmdlinepasswd=“$cmdlinepasswd”'
$0~“^[:space:][]*这应该可以做到:

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
只需将它们作为以下内容传递到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
awk-v RS=-v ORS='\n\n'-v datasource=“$datasource”-v cmdlinepasswd=“$cmdlinepasswd”'


$0~“^[:space:][]*是否要查找名为
datasource
variable的资源,并用
cmdlinepasswd
variable的内容替换其密码?@Birei:是的,这是必需的。感谢您的回复。
sed
这项任务会更困难吗。是否可以选择使用更强大的工具,如
perl
python
?@Birei:perl就可以了。sed是一个很好的工具,可以在一行上进行简单替换,但对于任何其他文本处理,您都应该使用awk。每条记录之间是否有两条虚线?请更新您发布的示例输入,使其与输入完全一致,包括每条记录之间的内容(如果有)。您只是说要更改具有特定
名称
值的记录中的密码,例如
jdbc/myDBPool1
?是否要查找名为
datasource
变量的资源,并用
cmdlinepasswd
变量的内容替换其密码?@Birei:是的,这是必需的。感谢您的回复。
sed
这项任务会更困难吗。是否可以选择使用更强大的工具,如
perl
python
?@Birei:perl就可以了。sed是一个很好的工具,可以在一行上进行简单替换,但对于任何其他文本处理,您都应该使用awk。每条记录之间是否有两条虚线?请更新您发布的示例输入,使其与输入完全一致,包括每条记录之间的内容(如果有)。您只是说要更改具有特定
名称
值(如
jdbc/myDBPool1
)的记录中的密码吗?谢谢。。这似乎很有效。您能告诉我如何更换(并保存)它吗。脚本现在在替换后回显输出。只是删除了注释并将此脚本用作。perl-pe'BEGIN{($datasource,$cmdlinepasswd)=(shift,shift)}if($range=(m/=“\Q${datasource}”/…/password=/){if(Q | E0 | eq substr$range,-2){s/(=”。(“\s*)$/$1${cmdlinepasswd 2/;}$$datasource cmdlinepasswd文件。xml@user2714227:与使用
sed时相同。开关
-i
对两者都有相同的含义。非常感谢您抽出时间,解决方案非常有效。。。非常感谢。。。!!这是我用过的。perl-i-pe'BEGIN{($datasource,$cmdlinepasswd)=(shift,shift)}if($range=(m/=“\Q${datasource}”/…/password=/){if(Q | E0 | eq substr$range,-2){s/(=”。(“\s*)$/$1${cmdlinepasswd 2/}}$$datasource cmdlinepasswd server.xmlYa,如前所述,使用双引号。。在上面的评论中漏掉了。谢谢。。这似乎很有效。您能告诉我如何更换(并保存)它吗。脚本现在在替换后回显输出。只是删除了注释并将此脚本用作。perl-pe'BEGIN{($datasource,$cmdlinepasswd)=(shift,shift)}if($range=(m/=“\Q${datasource}”/…/password=/){if(Q | E0 | eq substr$range,-2){s/(=”。(“\s*)$/$1${cmdlinepasswd 2/;}$$datasource cmdlinepasswd文件。xml@user2714227:与使用
sed时相同。开关
-i
对两者都有相同的含义。非常感谢您抽出时间,解决方案非常有效。。。非常感谢。。。!!这是我用过的。perl-i-pe'BEGIN{($datasource,$cmdlinepasswd)=(shift,shift)}if($range=(m/=“\Q${datasource}”/…/password=/){if(Q | E0 | eq substr$range,-2){s/(=”。(“\s*)$/$1${cmdlinepasswd 2/}}$$datasource cmdlinepasswd server.xmlYa,如前所述,使用双引号。。在上面的评论中遗漏了它。感谢您提供的解决方案。但是,如果我们把“name”放在某个地方,并且不在@user2714227的正下方,那会怎么样呢?这没有什么区别,脚本将按原样工作。::Ok ED.将检查一下。感谢您的及时帮助。当“name”、“=”和“datasourcename”之间没有空格(如name=“jdbc/myDBPool1”)时,上述awk脚本工作得非常好,没有任何问题,但真正的问题是当您有空格(如name=“jdbc/myDBPool1”)时,脚本无法执行搜索和替换。能溜溜球吗