我有一些部分包含XML数据的文本文件。 E.g:
<soap:Envelope xmlns:soap="..."><soap:Body><Data><SpecificTag>Some
multiline data
that I need to
extract.
</SpecificTag></Data></soap:Body></soap:Envelope>
我需要进行多行搜索并仅提取特定标记内的数据。我在这里尝试了一些解决方案,以及在perl-regexp模式下使用grep
获得的最佳结果:
grep -Pzo '(?s)<SpecificTag>\K.*?(?=</SpecificTag>)' filename
但有时文件可能包含两个或多个具有匹配模式的相同块。如何更改此正则表达式以将grep输出限制为第一次出现?在perl正则表达式模式下,-m
参数不起作用。
p.s。:其他工作解决方案没问题,但使用特定于XML的工具不是一种选择。文件实际上是使用strings
实用程序渗透的内存转储,它们仅包含SOAP事务的片段以及其他数据。在这种情况下我必须使用正则表达式。
答案 0 :(得分:2)
您需要使用\A
锚点来匹配第一行的开头。
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.
OR
grep -Pzo '(?s)\A.*?<SpecificTag>\K(?:(?!</?SpecificTag>).)*(?=</SpecificTag>)' file
答案 1 :(得分:0)
这里有一些关于sed的内容:
/<SpecificTag>/,/<\/SpecificTag>/ {
/<SpecificTag>/ {
s/.*<SpecificTag>//
}
/<\/SpecificTag>/ {
s/<\/SpecificTag>.*//
p
q
}
p
}
将其放入文件中,例如foo.sed
,然后使用sed -n -f foo.sed filename.xml
。
其工作方式如下:
/<SpecificTag>/,/<\/SpecificTag>/ {
表示所有这些只发生在<SpecificTag>
和</SpecificTag>
之间的行。
/<SpecificTag>/ {
s/.*<SpecificTag>//
}
表示在该约束中,包含<SpecificTag>
的行包含它,并删除它之前的所有内容。
/<\/SpecificTag>/ {
s/<\/SpecificTag>.*//
p
q
}
表示包含</SpecificTag>
的行包含它,删除后的所有内容都会被打印,然后退出。这就是提取第一个匹配的方式。
p
}
表示打印第一个约束(标记之间)中的所有其他行。这包括替换后第一行的其余部分。
如果您希望在一个长命令中使用它:
sed -n -e '/<SpecificTag>/,/<\/SpecificTag>/ { /<SpecificTag>/ { s/.*<SpecificTag>// }; /<\/SpecificTag>/ { s/<\/SpecificTag>.*//; p; q }; p }' filename.xml
...但当然这让人很难看到发生的事情,并且sed脚本已经非常难以阅读。
附录:您可能想要考虑的一个补充是
/<\/SpecificTag>/ {
s/<\/SpecificTag>.*//
p
q
}
进入
/<\/SpecificTag>/ {
s/<\/SpecificTag>.*//
/^$/ !p
q
}
或者甚至可能
/^ *$/ !p
...在这种情况下,包含</SpecificTag>
的行的其余部分只有在它不为空(第一个版本)或包含多个空格(第二个版本)时才会被打印。这可以防止(可能)在提取的文本末尾出现多余的换行符。