Bash 脚本中的多行正则表达式 XML 替换(可能通过 Perl)

Multiline Regex XML replacement in Bash script (likely via Perl)

我有一个 XML 文件,格式如下。

我想利用步骤名称,其中包含 VM 相关步骤中的字符 "VM"。当我在步骤名称中看到 "VM" 时,我想将计算机名称字段替换为 "VMname" 并将计算机 ID 字段替换为 "VMid."

我要

<step sequence="106" name="Patch%20Baseline">
   <!-- No parameters accepted for baseline steps -->
   <target-set>
    <computer name="nameAndIDTarget" id="123" />
  </target-set>
 </step>
 <step sequence="110" name="Warning%3A%20Outdated%20VMware%20Tools%20Version">
  <target-set>
    <computer name="nameAndIDTarget" id="123" />
  </target-set>
 </step>

成为

<step sequence="106" name="Patch%20Baseline">
  <!-- No parameters accepted for baseline steps -->
  <target-set>
    <computer name="nameAndIDTarget" id="123" />
  </target-set>
</step>
<step sequence="110" name="Warning%3A%20Outdated%20VMware%20Tools%20Version">
  <target-set>
    <computer name="VMname" id="VMid" />
  </target-set>
</step>

此函数将成为 bash 脚本的一部分,因此如果通过 Perl 完成,我更喜欢单行或内联方法。我是 Perl/Regex 愚蠢的,无法理解我迄今为止看到的例子。

给你

perl -pe 'if (m!<step .*name=".*VM!..m!</step>!){ if (m!<computer!){s/name=".*?"/name="VMname"/;s/id=".*?"/id="VMid"/} }' test.xml

留下参考以防投票的人不知道 Perl 魔法

perldoc flip-flop

这是我的解决方案 - 在我看来,这对于 one-liner 来说太复杂了。只需要调用一个perl脚本就很容易了。

$vm = ;                                         # $vm is set to 1 only if s step sequence with `VM` in is detected
while(<>) {                                     # Loop through the file, line by line
    if(m!<step sequence=.* name="(.*VM.*)">!) { # Check for sequence name containing VM
        $vm = 1;
     }
     if($vm == 1 && m!<computer name!) {        # Output special VM name   
         print qq!    <computer name="VMname" id="VMid" />\n!;
         $vm = 0;                               # Reset the VM flag
     } else {
         print $_;                              # Otherwise print the input line
     }
}

它没有回答 所问的问题 ,但正确的方法是使用 XML-aware 工具,例如 XMLStarlet:

xmlstarlet ed -u '//step[contains(@name, "VM")]/target-set/computer/@name' -v VMname \
              -u '//step[contains(@name, "VM")]/target-set/computer/@id' -v VMid \
  <in.xml >out.xml

请注意,这假定使用默认命名空间;如果在您的层次结构中更高的某个地方有一个 xmlns="..." 属性,则应该编辑问题以包括该属性。