Bash:正则表达式同时匹配多行并提取捕获的内容
Bash: Regex matching on multiple lines simultaneously and extracting captured content
我有一个 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解析相关解决方案
更新:根据 Steven 的建议,以下有效
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
考虑使用 XMLStarlet
"XMLStarlet is a set of command line utilities (tools) which can be
used to transform, query, validate, and edit XML documents and files
using simple set of shell commands in similar way it is done for plain
text files using UNIX grep, sed, awk, diff, patch, join, etc
commands."
XML 解析器,尤其是支持 XPath 的解析器将变得更加容易和稳定,但如果您真的必须坚持使用正则表达式,这里有一个模式可以与您的示例输入一起使用提供:
<starttag name="([^"])*"[^>]*>(\s|<innertag[^>]*>)*<innertag name="[^"]*" value="YYY"\/>(\s|<innertag[^>]*>)*<\/starttag>
它不适用于格式良好的 XML 文档的所有变体,但只要它们的格式与您的示例一致,您就应该 "okay".
默认情况下,正则表达式总是跨多行捕获。有一个选项,您可以告诉它一次只处理一行,但默认情况下通常不会打开。唯一真正的技巧是 .
模式不匹配换行符,所以如果你想匹配任何字符,包括换行符,你需要使用 .|\n
或一个否定字符class 例如[^>]
.
我有一个 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解析相关解决方案
更新:根据 Steven 的建议,以下有效
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
考虑使用 XMLStarlet
"XMLStarlet is a set of command line utilities (tools) which can be used to transform, query, validate, and edit XML documents and files using simple set of shell commands in similar way it is done for plain text files using UNIX grep, sed, awk, diff, patch, join, etc commands."
XML 解析器,尤其是支持 XPath 的解析器将变得更加容易和稳定,但如果您真的必须坚持使用正则表达式,这里有一个模式可以与您的示例输入一起使用提供:
<starttag name="([^"])*"[^>]*>(\s|<innertag[^>]*>)*<innertag name="[^"]*" value="YYY"\/>(\s|<innertag[^>]*>)*<\/starttag>
它不适用于格式良好的 XML 文档的所有变体,但只要它们的格式与您的示例一致,您就应该 "okay".
默认情况下,正则表达式总是跨多行捕获。有一个选项,您可以告诉它一次只处理一行,但默认情况下通常不会打开。唯一真正的技巧是 .
模式不匹配换行符,所以如果你想匹配任何字符,包括换行符,你需要使用 .|\n
或一个否定字符class 例如[^>]
.