从日志文件中提取一行的一部分

问题描述 投票:0回答:3

从输入中提取感兴趣的子字符串(如下所示)的最快方法是什么?

MsgTrace(65/26)noop:user=xxx=INBOX:cmd=534
ImapFetchComplete(56/39)user=xxxxxxxxxx

所需的输出(即本例中字符串

:
后面以
MsgTrace(65/26)
结尾的字符串):

noop

我尝试了以下方法,但没有成功:

egrep -i "[a-zA-Z]+\(.*\)[a-z]+:"
linux awk sed grep
3个回答
2
投票
当在给定输入行上找到匹配项时,

grep
默认返回整行

虽然选项

-o
将输出限制为仅正则表达式匹配的行的部分,但在本例中这仍然不够,因为您需要该匹配的 substring

但是,由于您使用的是 Linux,您可以使用 GNU

grep
-P
选项(用于支持 PCREs,Perl 兼容的正则表达式),它允许通过以下功能提取 submatch作为
\K
(删除到目前为止匹配的所有内容)和
(?=...)
(对匹配没有贡献的前瞻断言):

$ grep -Po  "[a-zA-Z]\(.*\)\K[a-z]+(?=:)" <<'EOF'
MsgTrace(65/26)noop:user=xxx=INBOX:cmd=534
ImapFetchComplete(56/39)user=xxxxxxxxxx
EOF
noop  # output

可选背景信息:

Ed Morton 指出(在一条已删除的评论中)GNU

grep
man
页面仍然将
-P
选项称为“高度实验性”,可能“警告未实现的功能”,但该选项已已经存在多年了,实际上我还没有看到警告或性能问题 - YMMV。

在当前的情况下,上述命令甚至优于

sed
awk
解决方案 - 请参阅 NeronLeVelu 有用的性能比较

这篇有趣的文章 Ed 指出讨论了可以 与正则表达式引擎一起出现的潜在性能问题,例如

grep -P
(通过 PCRE 库)、Perl 本身以及许多其他广泛使用(且成熟)的正则表达式引擎所使用的,例如在 Python、Ruby 和 PHP 中:

  • 简而言之:这些引擎采用的递归回溯算法可能会导致“病态”正则表达式严重性能下降,这些正则表达式将长序列的子表达式与可变长度量词串在一起,例如(较长版本的)
    a?a?a?a?aaaa
    来匹配
     aaaa
  • 本文认为,只有当正则表达式包含反向引用时才真正需要回溯,并且在不存在反向引用的情况下应该采用不同的、更快的算法。

2
投票

你可以试试这个:

$ sed -n 's/[[:alpha:]]*([^)]*)\([[:lower:]]*\):.*/\1/p' file
noop

它可移植到所有 POSIX sed,并且不使用 PCRE,仅使用 BRE,因此正则表达式匹配部分至少应该很快。


2
投票

对此类示例条目的 2469120 行文本进行快速而肮脏的测试,将

grep -PO
作为获胜者

time sed -n -e 's/^MsgTrace[^)]\{4,\})//;t M' -e 'b' -e ':M' -e 's/:.*//p' YourFile >/dev/null
real    0m7.61s
user    0m7:10s
sys     0m0.13s

time awk -F ':' '/^MsgTrace/{ sub( /.*)/, "", $1); print $1}' YourFile >/dev/null
real    0m17.43s
user    0m16.19s
sys     0m0.17s

time grep -Po  "[a-zA-Z]\(.*\)\K[a-z]+(?=:)" YourFile >/dev/null
real    0m6.72s
user    0m6.23s
sys     0m0.11s

time sed -n 's/[[:alpha:]]*([^)]*)\([[:lower:]]*\):.*/\1/p' YourFile >/dev/null
real    0m17.43s
user    0m16.29s
sys     0m0.12s

time grep -Po '(?<=MsgTrace\(65/26\)).*?(?=:)' YourFile >/dev/null
real    0m16.38s
user    0m15.22s
sys     0m0.15s

对于@EdMorton 问题(我重做相同的原始 sed 以在相同的机器负载上下文中具有比较值)。确切的字符串要快得多,我想 sed 在选择所有标准中最长的一个之前会尝试几种组合,其中

.*l
pool is full

提供更多的可能性
time sed -n -e 's/^MsgTrace([^)]\{3,\})//;T' -e 's/:.*//p' YourFile >/dev/null
real    0m7.28s
user    0m6.60s
sys     0m0.13s

time sed -n -e 's/^[[:alpha:]]*([^)]\{3,\})//;T' -e 's/:.*//p' YourFile >/dev/null
real    0m10.44s
user    0m9.67s
sys     0m0.14s

time sed -n -e 's/^[[:alpha:]]*([^)]*)//;T' -e 's/:.*//p' YourFile >/dev/null

real    0m10.54s
user    0m9.75s
sys     0m0.11s
© www.soinside.com 2019 - 2024. All rights reserved.