具有特定文本的多行 grep

Multiline grep with specific text

有一个 xml 文件,里面有很多 <A_tag>-s。

我需要查看至少有一个 <C_tag>.

的那些 A 标签(及其子标签,因此标签的全部内容)

所以这个块应该匹配(因此包含在结果中):

<A_tag>
    ...
    ...
    <C_tag attr1="" ... attrn="" />
    ...
</A_tag>

我试过使用 pcregrep,但我不知道如何判断任何块结尾,它比 1 个字符长(</A_tag> 比那个长,但是例如 [^>] 正则表达式对我来说也很容易)。

我也试过 awk,但也无法达到目标。

如果有经验的人可以帮助我,请让你的命令也用空行分隔找到的块,这样我可以学到更多。

跟进 xmllint 评论:

xmllint --xpath '(//A_tag/C_tag/..)' x.xml

会在A_TAG下寻找C_TAG,然后显示父A_TAG。

输出:

<A_tag>
    <C_tag attr1="" attrn=""/>
</A_tag>

是的,就我而言,这就是解决方案:

xmllint --shell x.xml <<< 'xpath //A_tag//C_tag/ancestor::A_tag'

因为我的xmllint版本不支持--xpath选项。 此外,C_tag 可以是 A_tag 的任何后代,而不仅仅是直接 child(我没有在问题中澄清)。 但是,dash-o的答案似乎是正确的。

我唯一的问题是我正在使用的这个 xml 文件包含 450 万行,其中 xmllint 结果很慢 - 因为它确实解析了文件。

如果您有适用于 awkpcregrep 的更通用的解决方案,请与我分享。他们在这里会很好,因为他们只处理模式。

要不然我明天就采纳原答案了

如果文件打印精美(或遵循类似规则),可以编写小的 awk 脚本,并且只作用于 a_tag 和 c_tag 行:

awk '
/<A_tag>/      { in_a=[=10=] ; c="" ; next }
in_a           { in_a = in_a RS [=10=]}
/<C_tag/       { c=[=10=] ; next }
/<\/A_tag>/    { if ( in_a && c ) { print in_a ; in_a="" ; c=""} }
' x.xml