将grep regex多行搜索的匹配结果限制为1

将grep regex多行搜索的匹配结果限制为1,regex,linux,command-line,grep,pcre,Regex,Linux,Command Line,Grep,Pcre,我有一些部分包含XML数据的文本文件。例如: <soap:Envelope xmlns:soap="..."><soap:Body><Data><SpecificTag>Some multiline data that I need to extract. </SpecificTag></Data></soap:Body></soap:Envelope> 但有时文件可能包含两个或多个具有匹配模式的相

我有一些部分包含XML数据的文本文件。例如:

<soap:Envelope xmlns:soap="..."><soap:Body><Data><SpecificTag>Some
multiline data
that I need to
extract.
</SpecificTag></Data></soap:Body></soap:Envelope>
但有时文件可能包含两个或多个具有匹配模式的相同块。如何更改此正则表达式以将grep输出限制为第一次出现
-m
参数在perl正则表达式模式下不起作用


p、 美国:其他可行的解决方案也可以,但使用特定于XML的工具不是一个选项。文件实际上是渗透了
字符串
实用程序的内存转储,它们只包含SOAP事务片段和其他数据。在这种情况下,我必须使用正则表达式。

这里有一些关于sed的东西:

/<SpecificTag>/,/<\/SpecificTag>/ {
  /<SpecificTag>/ {
    s/.*<SpecificTag>//
  }
  /<\/SpecificTag>/ {
    s/<\/SpecificTag>.*//
    p
    q
  }
  p
}
这意味着所有这些只发生在
之间的行上

表示打印第一个约束内(标记之间)的所有其他行。这包括替换后第一行的其余部分

如果您希望将其放在一个长命令中:

sed -n -e '/<SpecificTag>/,/<\/SpecificTag>/ { /<SpecificTag>/ { s/.*<SpecificTag>// }; /<\/SpecificTag>/ { s/<\/SpecificTag>.*//; p; q }; p }' filename.xml

…在这种情况下,仅当包含
的行不是空的(第一个版本)或包含多于空格的(第二个版本)时,才会打印该行的其余部分。这可以防止(可能)在提取文本的结尾出现多余的换行。

您需要使用
\A
锚定来匹配第一行的开头

grep -Pzo '(?s)\A.*?<SpecificTag>\K.*?(?=</SpecificTag>)' file
grep-Pzo'(?s)\A.*?\K.*(?=)文件
示例:

$ cat file
<soap:Envelope xmlns:soap="..."><soap:Body><Data><SpecificTag>Some
multiline first data
that I need to
extract.
</SpecificTag></Data></soap:Body></soap:Envelope>
<SpecificTag>Some
multiline second data
that I need to
extract.
$cat文件
一些
多行优先数据
我需要
摘录
一些
多行秒数据
我需要
摘录
$grep-Pzo'(?s)\A.*?\K.*(?=)文件
一些
多行优先数据
我需要
摘录

grep-Pzo'(?s)\A.*\K(?:(?!)*(?=)文件

非常有魅力,非常感谢您的详细解释!如果我关闭输入文件中的第二个
SpecificTag
,这不会将输出限制为第一个文件中的数据。我认为这不起作用。将
添加到
文件的末尾,然后再次运行grep命令。您将获得两次多行数据(每个标记一次)。我担心新的数据与旧的数据一样,不管我是否提供有效的XML。在任何情况下,OP都不是在解析有效的XML,而是在清理内存转储。这取决于OP,而不是我。grep和sed都不是解析xml文件的正确工具。感谢Avinash Raj,但Wintermute是正确的:在我的例子中,重复的数据完全符合模式,它在每次出现时都有开始和结束标记。如果在示例的末尾添加结束标记,则两个表达式的结果仍将包含两个重复项。
  /<\/SpecificTag>/ {
    s/<\/SpecificTag>.*//
    p
    q
  }
  p
}
sed -n -e '/<SpecificTag>/,/<\/SpecificTag>/ { /<SpecificTag>/ { s/.*<SpecificTag>// }; /<\/SpecificTag>/ { s/<\/SpecificTag>.*//; p; q }; p }' filename.xml
  /<\/SpecificTag>/ {
    s/<\/SpecificTag>.*//
    p
    q
  }
  /<\/SpecificTag>/ {
    s/<\/SpecificTag>.*//
    /^$/ !p
    q
  }
    /^ *$/ !p
grep -Pzo '(?s)\A.*?<SpecificTag>\K.*?(?=</SpecificTag>)' file
$ cat file
<soap:Envelope xmlns:soap="..."><soap:Body><Data><SpecificTag>Some
multiline first data
that I need to
extract.
</SpecificTag></Data></soap:Body></soap:Envelope>
<SpecificTag>Some
multiline second data
that I need to
extract.
$ grep -Pzo '(?s)\A.*?<SpecificTag>\K.*?(?=</SpecificTag>)' file
Some
multiline first data
that I need to
extract.
grep -Pzo '(?s)\A.*?<SpecificTag>\K(?:(?!</?SpecificTag>).)*(?=</SpecificTag>)' file