模式匹配后如何删除匹配的块

时间:2019-06-24 05:45:40

标签: xml shell sed xmlstarlet

这是文件(命名为sample.xml):


<?xml version="1.0" encoding="UTF-8"?>
<configs>

    <blah1 value="ma">
      <tag3>100MB</tag3>
    </blah1>

    <blah1 value="ba">
      <tag3>20MB</tag3>
    </blah1>

     <blah2 value="*" version="1.0" result="true">
        <blah1 value="xyz">
          <blah1 value="uvw" result="true">
             <tag>4</tag>
          </blah1>
        </blah1>
     </blah2>

  <!-- This is tag with def value -->
  <blah2 value="*" version="2.0" result="true">
    <blah1 value="abc">
      <blah1 value="def" result="true">
        <tag2>on</tag2>
      </blah1>
    </blah1>
  </blah2>

</configs>

使用value="def"查找字符串时,请从<blah2> to </blah2>标记开始删除整个块

我不熟悉sed保持模式,但是我从Google那里得到的东西非常接近

sed -n '/<blah2.*>/,/<\/blah2>/{
                                  H
                                  /<\/blah2>/ { 
                                        s/.*//;x
                                       /def/d
                                       p 
                                  }
                               }' sample.xml

预期结果:


<?xml version="1.0" encoding="UTF-8"?>
<configs>

    <blah1 value="ma">
      <tag3>100MB</tag3>
    </blah1>

    <blah1 value="ba">
      <tag3>20MB</tag3>
    </blah1>

     <blah2 value="*" version="1.0" result="true">
        <blah1 value="xyz">
          <blah1 value="uvw" result="true">
             <tag>4</tag>
          </blah1>
        </blah1>
     </blah2>

</configs>

实际结果(带有上述无效的sed):

     <blah2 value="*" version="1.0" result="true">
        <blah1 value="xyz">
          <blah1 value="uvw" result="true">
             <tag>4</tag>
          </blah1>
        </blah1>
     </blah2>

3 个答案:

答案 0 :(得分:3)

使用xmlstarlet删除第二个标签blah2

xmlstarlet edit --delete '//configs[blah2[2]/blah1/blah1[@value="def"]]/blah2[2]' file.xml

输出:

<?xml version="1.0" encoding="UTF-8"?>
<configs>
  <blah1 value="ma">
    <tag3>100MB</tag3>
  </blah1>
  <blah1 value="ba">
    <tag3>20MB</tag3>
  </blah1>
  <blah2 value="*" version="1.0" result="true">
    <blah1 value="xyz">
      <blah1 value="uvw" result="true">
        <tag>4</tag>
      </blah1>
    </blah1>
  </blah2>
</configs>

如果要就地编辑文件,请添加选项-L。


使用过的XPath的解释:

//configs[blah2[2]/blah1/blah1[@value="def"]]/blah2[2]
|---A---| |-------------B------------------| |---C---|
  

A和B:您要查找的属性的路径

     

A和C:要删除的标签的路径

答案 1 :(得分:1)

这可能对您有用(GNU sed):

sed '/<blah2.*>/{:a;N;/<\/blah2.*>/!ba;/value="def"/d}' file

如果一行包含<blah2.*>,请收集所有行,直到一行包含<\/blah2.*>,然后测试这些行中的字符串value="def",如果找到,则删除这些行。

答案 2 :(得分:0)

由于您对sed解决方案感到满意,鉴于您发布的示例输入/输出,这是一个更好的选择(更清晰,更便携等):

$ awk -v RS= -v ORS='\n\n' '!/value="def"/' file
<?xml version="1.0" encoding="UTF-8"?>
<configs>

    <blah1 value="ma">
      <tag3>100MB</tag3>
    </blah1>

    <blah1 value="ba">
      <tag3>20MB</tag3>
    </blah1>

     <blah2 value="*" version="1.0" result="true">
        <blah1 value="xyz">
          <blah1 value="uvw" result="true">
             <tag>4</tag>
          </blah1>
        </blah1>
     </blah2>

</configs>

如果这不是您所需要的,那么有什么更好的awk替代方案来满足您的需要,因为sed仅适合对单个字符串执行s / old / new。