我的服务器上有一个巨大的日志文件(数十GB)。它太大,无法在合理的时间内下载。然而,我实际上只对相对较小的线条子集感兴趣。日志文件具有类似 xml 的结构。有很多<log>...</log>
条目,其中之一有我正在寻找的特定模式,可以说"Failure"
(当grep
我"Failure"
只有 1 个匹配项时):
<log>...</log>
<log>...</log>
....
<log> (*1*)
...
... "Failure" ...
...
</log> (*2*)
....
<log>...</log>
<log>...</log>
我的想法是分别搜索包含 的行的前一个和下一个出现位置<log>
(*1*)
以及之前和之后的位置。之后我想将这些行复制到一个单独的文件中,然后我可以轻松下载该文件。</log>
(*2*)
"Failure"
伪代码总结:
failure_line = find pattern "Failure" in log file
start_line = find immediate previous occurrence of <log> before the line failure_line
finish_line = find immediate next occurrence of </log> after the line failure_line
copy all lines from start_line until finish_line to a new file
这可以通过脚本来实现bash
而不需要很大的开销吗?
答案1
请注意,标准文本处理工具(如sed
、perl
或 )awk
并不用于 XML 解析。如果你可以依赖一些东西,比如<log>...</log>
一行中不超过一对,你可以这样做sed
:
sed '/<log>.*<\/log>/{/Failure/p;d;};/<log>/,/<\/log>/H;/<log>/h;/<\/log>/!d;x;/Failure/!d' your.log
- '/.*</log>/' 将行与完整的标记匹配。这些需要单独处理:
/Failure/p
如果它们包含 则打印它们Failure
,d
停止进一步处理。 - 现在
/<log>/,/<\/log>/
选择开头<log>
和结尾之间的行</log>
并将它们附加到保留空间( 的剪贴板sed
)H
/<log>/h
log
初始化任何新序列的保留空间/<\/log>/!d
停止处理所有行,但那些有关闭的行</log>
- 因此,仅在关闭日志时执行以下操作:
x
交换保持空间和模式空间,因此我们拥有自上一行以来收集的模式空间中的所有内容<log>
。d
如果不包含则删除它Failure
,否则默认情况下会在脚本末尾打印