如何扫描多个日志文件以查找哪些日志文件中包含特定的IP地址?

时间:2009-01-12 00:18:05

标签: perl search file grep

最近有一些攻击者在我的服务器上尝试恶意攻击,所以我决定稍微“跟踪”它们,即使我知道它们不会走得太远。

现在,我有一个包含服务器日志的整个目录,我需要一种方法来搜索目录中的每个文件,并在找到字符串时返回文件名。所以我想,对于文本和文本来说,用什么语言更好?文件操作比Perl?所以我的朋友正在帮助我使用脚本来扫描某个IP的所有文件,并返回包含IP的文件名,这样我就不必手动搜索每个日志的攻击者了。 (我有数百人)

#!/usr/bin/perl

$dir = ".";

opendir(DIR, "$dir");
@files = grep(/\.*$/,readdir(DIR));
closedir(DIR);

foreach $file(@files) {
    open FILE, "$file" or die "Unable to open files";

    while(<FILE>) {
        print if /12.211.23.200/;
    }

}

虽然它给我目录读取错误。非常感谢任何帮助。

编辑:代码编辑,仍然说权限被拒绝无法打开第10行的目录。如果您质疑目录更改为“。”,我将从日志目录中运行脚本。

麦克

14 个答案:

答案 0 :(得分:14)

您可以改用grep吗?

答案 1 :(得分:5)

要获得IP的所有行,我会直接使用 grep ,不需要显示文件列表,这是一个简单的命令:

grep 12\.211\.23\.200 *

我喜欢将它传播到另一个文件,然后在编辑器中打开该文件......

如果你坚持想要文件名,那也很容易

grep -l 12\.211\.23\.200 *

grep可用于所有Unix //使用GNU工具的Linux,或使用众多实现之一(unxutils,cygwin等等)在Windows上使用

答案 2 :(得分:3)

使用通过$dirname找到的文件时,您必须将$filnamereaddir连接起来,请记住您没有chdir加入这些文件所在的目录。< / p>

open FH, "<", "$dirname/$filname" or die "Cannot open $filname:$!";

顺便说一句,为什么不使用grep -r以递归方式搜索日志目录下的所有子目录作为字符串?

编辑:我看到了您的修改,还有两件事。首先,这一行:

@files = grep(/\.*$/,readdir(DIR));

无效,因为您在字符串末尾搜索零个或多个.个字符。因为它是零或更多,它将匹配目录中的所有内容。如果您尝试排除以.结尾的文件,请尝试以下操作:

@files = grep(!/\.$/,readdir(DIR));

如果您尝试排除这些文件,请注意!符号否定。否则(如果你只想要那些文件并且我误解了你的意图),请离开!

在任何情况下,如果您在第10行收到die消息,则很可能是您遇到的文件具有无法读取的权限。尝试将文件名放在die输出中,这样你就可以看到它失败的文件:

open FILE, "$file" or die "Unable to open file: $file";

但与其他答案一样,并重申:为什么不使用grep? unix命令,而不是Perl函数。

答案 3 :(得分:2)

这将获得你在perl中寻找的文件名,并且可能比运行和执行perl正则表达式要快得多。

@files = `find ~/ServerLogs -name "*.log" | xargs grep -l "<ip address>"`'

虽然这需要符合* nix标准的系统,或Windows上的Cygwin。

答案 4 :(得分:1)

首先获取源目录中的文件列表:

opendir(DIR, "$dir");
@files = grep(/\.log$/,readdir(DIR));
closedir(DIR);

然后循环浏览这些文件

foreach $file(@files)
{
  // file processing code
}

答案 5 :(得分:1)

我的第一个建议是使用grep代替。他们说这是工作的正确工具......

但要回答你的问题:

readdir只返回目录中的文件名。您需要将目录名和文件名连接在一起。

$path = "$dirname/$filname";
open FH, $path or die ...

然后你应该忽略实际上是目录的文件,例如“。”和“......”。获取$ path后,检查它是否是文件。

if (-f $path) {
    open FH, $path or die ...
    while (<FH>)

答案 6 :(得分:1)

顺便说一下,我想我会提到File :: Next。迭代目录中的所有文件(递归地):

use Path::Class; # always useful.
use File::Next;

my $files = File::Next::files( dir(qw/path to files/) ); # look in path/to/files
while( defined ( my $file = $files->() ) ){
    $file = file( $file );
    say "Examining $file";
    say "found foo" if $file->slurp =~ /foo/;
}

File :: Next是污点安全的。

答案 7 :(得分:0)

〜不会在Perl中自动扩展。

opendir my $fh,  '~/' or die("Doin It Wrong");  # Doing It Wrong. 

opendir my $fh, glob('~/') and die( "Thats right!" );

答案 8 :(得分:0)

另外,如果必须使用readdir(),请务必保护表达式:

while (defined(my $filename = readdir(DH))) {
    ...
}

如果你没有进行defined()测试,如果找到一个名为'0'的文件,循环将终止。

答案 9 :(得分:0)

您是否在CPAN上查看了日志解析器?我用'log parse'搜索了它,它产生了超过200次点击。有些(可能很多)不相关 - 有些可能是。这部分取决于您使用的Web服务器。

答案 10 :(得分:0)

我读到这个吗?你的第10行给出了错误

open FILE, "$file" or die "Unable to open files";

根据第6行,你想要阅读的$文件

@files = grep(/\.*$/,readdir(DIR));

以零点或多点结尾的文件。这是你真正想要的吗?这基本上匹配目录中的每个文件,包括“。”和“......”。也许你没有足够的权限打开父目录进行阅读?

编辑:如果您只想阅读所有文件(包括隐藏文件),您可能需要使用以下内容:

opendir(DIR, ".");
@files = readdir(DIR);
closedir(DIR);

foreach $file (@files) {
  if ($file ne "." and $file ne "..") {
    open FILE, "$file" or die "cannot open $file\n";
    # do stuff with FILE
  }
}

请注意,这不会处理子目录。

答案 11 :(得分:0)

我知道我在这次讨论中已经迟到了(在搜索grep相关帖子时遇到了它)但我还是会回答:

如果这些是Web服务器日志(Apache,IIS,W3SVC等),则没有明确说明,但是用于挖掘数据的最佳工具是Microsoft的LogParser工具。有关详细信息,请参阅logparser.com。

LogParser允许您针对日志文件编写类似SQL的语句。它非常灵活,速度非常快。

答案 12 :(得分:0)

从命令行使用perl,就像更好的grep

perl -wnl -e'/12.211.23.200/并打印;' * .log&gt; output.txt的

这里的好处是你可以更容易地链接逻辑

perl -wnl -e'(/12.211.23.20 [1-11] /或/ denied / i)并打印;' * .LOG

如果您感觉很古怪,您还可以使用更高级的命令行选项将perl one liner结果提供给其他perl one衬里。

你真的需要阅读“Minimal Perl:For UNIX and Linux People”,这本书非常棒。

答案 13 :(得分:-1)

首先,使用grep

但如果你不想,这里有两个小改进,你可以做到我还没有看到提到:

1)改变:

@files = grep(/\.*$/,readdir(DIR));

@files = grep({ !-d "$dir/$_" } readdir(DIR));

通过这种方式,您不仅可以排除“。”和“..”以及服务器日志目录中可能存在的任何其他子目录(否则open下游会阻塞它们。)

2)改变:

print if /12.211.23.200/;

print if /12\.211\.23\.200/;

.”是一个正则表达式的通配符,意思是“任何字符”。将其更改为“\.”将减少误报的数量(在实践中不太可能改变您的结果,但无论如何它都更正确。)