我有一个如下所示的日志文件:
2010-05-12 12:23:45 Some sort of log entry
2010-05-12 01:45:12 Request XML: <RootTag>
<Element>Value</Element>
<Element>Another Value</Element>
</RootTag>
2010-05-12 01:45:32 Response XML: <ResponseRoot>
<Element>Value</Element>
</ResponseRoot>
2010-05-12 01:45:49 Another log entry
我想要做的是提取请求和响应XML(并最终将它们转储到自己的单个文件中)。我有一个使用egrep的类似解析器,但XML全部在一行上,而不是像上面那样的多个。
日志文件也有点大,每日记录500-600兆。我会通过PHP脚本读取较小的日志并使用正则表达式匹配,但是这样一个大文件所需的内存量很可能会破坏脚本。
是否有一种简单的方法可以使用Linux机箱上的内置工具(在本例中为CentOS)来提取多行,或者我将不得不咬紧牙关并使用Perl或PHP来读取整个文件中的内容提取它?
答案 0 :(得分:2)
# Example usage:
# perl script.pl data.xml RootTag > RootTag.xml
use strict;
use warnings;
my $tag = pop;
while (<>){
if ( s/.*(<$tag>)/$1/ .. s/(<(\/)$tag>).*/$1/ ){
print;
last if $2;
}
}
有关flip-flop operator的详细信息,请参阅文档。
答案 1 :(得分:2)
听起来像sed
的工作(我很想说SuperSed; - )
sed -n '/^<.\+>/H; /\(Request\|Response\) XML/{s/^.*</</;x;p}; ${x;p}' xmllog
其中xmllog
是您的日志文件的名称。您会在开头看到一个空行,但可以使用egrep '.+'
或仅tail -n +2
过滤掉。
作为解释,sed
是程序的一个小解释器,它由一系列匹配条件和相应的动作组成。 sed
逐行运行文件(因此名称为“流编辑器” - >“sed”),对于每一行,对于程序中与行上文本匹配的每个条件,它都适用于相应的行动。在这种情况下:
/^<.\+>/
是一个正则表达式条件,匹配包含<
后跟任何重复一次或多次(.
)后跟\+
的字符(>
)的行。基本上任何带有XML标记的行。关联的操作是H
,它将该行附加到“保持缓冲区”。另一个条件是
/\(Request\|Response\) XML/
当然,它是一个正则表达式,匹配Request
或Response
后跟空格,然后是XML
。相应的行动是
{s/^.*</</;x;p}
首先对行的开头(s
)进行替换(^
),后跟任意次重复的任何字符(.
)(*
)后跟<
,只有<
。基本上,在行上的第一个XML标记之前删除任何东西。然后它用“保持缓冲区”(包含上一条日志消息的XML)切换(x
)刚刚读取的行,并打印(p
)刚刚从保留中交换的内容缓冲。最后,
$
匹配输入的结尾,{x;p}
再次将保持缓冲区的内容交换到“打印缓冲区”,然后打印出来。
您可以更改命令以满足您的需要,例如,如果您需要某些内容来划分不同的记录,这将在它们之间添加一个空行:
sed -n '/^<.\+>/H; /\(Request\|Response\) XML/{s/^.*</\n</;x;p}; ${x;p}' xmllog
(当然,在这种情况下,请不要使用egrep
过滤掉开头的空白行。)
答案 2 :(得分:1)
你的问题暗示你没有正确思考;如果有办法用一种语言(有)做你所要求的......那么你可以用任何语言来做。
没有理由将整个日志读入内存。您只需逐行阅读并提取所需信息。您只需要保持状态(不在标签中,RootTag内部,ResponseRoot内部等)并根据需要处理数据。