Bash:同时在多行上进行正则表达式匹配并提取捕获的内容

时间:2016-01-28 13:19:29

标签: regex bash grep multiline pcregrep

我有以下格式的xml文件

<starttag name="AAA" >
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="YYY"/>
</starttag>
<starttag name="BBB" >
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="XXX"/>
</starttag>
<starttag name="CCC" >
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="YYY"/>
</starttag>
..
..
..

我想提取starttag的所有名称属性,其中任何一个innertag的值都是YYY。

所以在上面的文件中,输出将是AAA和CCC。 我只能使用正则表达式匹配。我想可以使用前瞻但不能为多行创建正则表达式模式。我知道如何使用正则表达式单行,我也尝试使用相同的但没有获得预期的输出。任何人都有进展。

编辑:虽然我已经放了xml示例,但实际上我正在尝试了解多行正则表达式匹配,我正在尝试这个文件,我失败了。请避免使用与XML解析相关的解决方案。

更新:根据史蒂文的建议,继续工作

pcregrep -M '<starttag name="([^"])*"[^>]*>(\s|<innertag[^>]*>)*<innertag name="[^"]*" value="YYY"\/>(\s|<innertag[^>]*>)*<\/starttag>' file.xml

grep -Pzo '<starttag name="([^"])*"[^>]*>(\s|<innertag[^>]*>)*<innertag name="[^"]*" value="YYY"\/>(\s|<innertag[^>]*>)*<\/starttag>' file.xml

2 个答案:

答案 0 :(得分:1)

考虑使用XMLStarlet

  

&#34; XMLStarlet是一组命令行实用程序(工具)   用于转换,查询,验证和编辑XML文档和文件   使用简单的shell命令集以类似的方式为plain执行   使用UNIX grep,sed,awk,diff,patch,join等文本文件   命令&#34;

答案 1 :(得分:0)

XML解析器,尤其是支持XPath的XML解析器将更容易和更稳定,但如果你真的必须坚持使用正则表达式,这里的模式将与你提供的示例输入一起使用:

<starttag name="([^"])*"[^>]*>(\s|<innertag[^>]*>)*<innertag name="[^"]*" value="YYY"\/>(\s|<innertag[^>]*>)*<\/starttag>

它不适用于格式良好的XML文档的所有变体,但只要它们像您的示例一样格式化,您就应该“好”。

默认情况下,正则表达式始终捕获多行。有一个选项,您可以告诉它一次只处理一行,但默认情况下通常不会打开。唯一真正的诀窍是.模式与换行符不匹配,因此如果要匹配任何字符(包括换行符),则需要使用.|\n或否定字符诸如[^>]之类的课程。