使用logstash grok过滤器提取文件路径的一部分的正则表达式

5
我是正则表达式的新手,但我认为这里的人们可能会给我有价值的建议。我正在使用logstash grok 过滤器,在其中只能提供正则表达式。
我有一个像这样的字符串:
/app/webpf04/sns882A/snsdomain/logs/access.log

我想用正则表达式从字符串中获取第三个"/"之后的子字符串sns882A,该如何做?
由于grok仅接受正则表达式,因此我受限于使用正则表达式。是否可能使用正则表达式来实现这一点?
5个回答

6

是的,您可以使用正则表达式通过Grok获取所需内容:

/[^/]+/[^/]+/(?<field1>[^/]+)/

我知道这个答案太晚了,但还是要点赞,因为它是第一个正确的答案。也就是说,使用命名捕获来提取它应该提取的部分的独立正则表达式(没有其他代码和分隔符)。 - Alan Moore

2

针对你的正则表达式:

    /\w*\/\w*\/(\w*)\/

您也可以使用以下测试工具: http://www.regextester.com/ 通过谷歌搜索正则表达式测试工具,您可以找到不同的用户界面。

从http://www.regextester.com/上我没有找到匹配项,我尝试了http://gskinner.com/RegExr/,但那里也没有结果... - flyasfish
此解决方案依赖于目录和文件名始终由字母数字字符或下划线组成。特别地,在路径中任何位置都不应存在空格。 - Borodin
匹配是基于索引0的。您还可以看到:1:(sns882A),这意味着它是第一个匹配。 - junky
当使用 /\w/\w/(\w*)/ 作为 grok 过滤器时,可能会出现 grok 解析失败错误,原因是没有匹配项。 - flyasfish

0
这是我在Perl中的做法:
my ($name) = ($fullname =~ m{^(?:/.*?){2}/(.*?)/});

编辑: 如果你的框架不支持 Perl 风格的非捕获组 (?:xyz),那么可以使用这个正则表达式代替:

^/.*?/.*?/(.*?)/

如果你关心.*?的性能,这个方法同样有效:

^/[^/]+/[^/]+/([^/]+)/

另外需要注意: 上述所有的正则表达式都将匹配字符串/app/webpf04/sns882A/

但是匹配字符串与第一个匹配组完全不同,在这三种情况下,第一个匹配组都是sns882A


当我在http://gskinner.com/RegExr/上尝试使用^(?:/.*?){2}/(.*?)/部分时,它匹配到/app/webpf04/sns882A/。 - flyasfish
你应该使用 (?:/[^/]*)。否则,你的正则表达式可能需要很长时间才能确定它不匹配。 - Borodin
这就是为什么我使用 .*? 的原因 - 为了避免贪婪匹配,因为它可能非常慢。 - mvp
当我将^(?:/.?){2}/(.?)/输入到grok过滤器中时,确认我得到了字符串/app/webpf04/sns882A/的部分。 - flyasfish
请注意,匹配字符串与第一个匹配组不同。请查看我的修改后的答案。 - mvp
OP 没有要求使用 Perl。 - Chris F

0
如果你确实在使用Perl,那么你应该像这样使用File::Spec模块。
use strict;
use warnings;

use File::Spec;

my $path = '/app/webpf04/sns882A/snsdomain/logs/access.log';
my @path = File::Spec->splitdir($path);

print $path[3], "\n";

输出

sns882A

我不能使用任何语言,这是logstash-grok配置的一部分,在其中我只能提供表达式。 - flyasfish

0

同样的答案,但修复了一个小错误。如果您在开头没有指定 ^,它将转到下一个匹配项(尝试添加更多 / 以获得更长的输入路径)。要修复它,只需在开头添加 ^,像这样。 ^ 表示输入行的开头。最后,group1 就是您的答案。

^/[^/]+/[^/]+/([^/]+)/

如果您正在使用任何URI路径,请使用以下内容(它将处理路径以及URI)。

^.*?/[^/]+/[^/]+/([^/]+)/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接