1

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

现在,我有一个包含服务器日志的完整目录,我需要一种方法来搜索目录中的每个文件,如果找到字符串则返回文件名。所以我心想,有什么比 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 行说权限被拒绝无法打开目录。如果您质疑目录更改为“。”,我将在日志目录中运行脚本。

麦克风。

4

14 回答 14

14

你可以用grep代替吗?

于 2009-01-12T00:23:22.347 回答
5

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

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

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

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

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

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

于 2009-01-12T10:50:31.567 回答
3

使用通过 找到的文件时 ,您必须$dirname与连接,记住您还没有进入这些文件所在的目录。$filnamereaddirchdir

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

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

编辑:我看到你的编辑,还有两件事。首先,这一行:

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

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

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

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

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

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

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

于 2009-01-12T00:25:07.057 回答
2

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

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

虽然,这需要一个兼容 *nix 的系统,或者 Windows 上的 Cygwin。

于 2009-01-12T00:22:39.103 回答
1

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

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

然后遍历这些文件

foreach $file(@files)
{
  // file processing code
}
于 2009-01-12T00:22:58.027 回答
1

我的第一个建议是使用 grep 代替。他们说,适合这项工作的工具……

但要回答你的问题:

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

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

然后您应该忽略实际上是目录的文件,例如“。” 和 ”..”。得到 $path 后,检查它是否是一个文件。

if (-f $path) {
    open FH, $path or die ...
    while (<FH>)
于 2009-01-12T00:28:06.830 回答
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 是安全的。

于 2009-01-12T12:47:40.910 回答
0

我知道我在这个讨论中已经很晚了(在搜索 grep 相关帖子时遇到了它),但无论如何我都会回答:

如果这些是 Web 服务器日志(Apache、IIS、W3SVC 等)并没有明确说明,但挖掘这些数据以获取数据的最佳工具是 Microsoft 的 LogParser 工具。有关更多信息,请参阅 logparser.com。

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

于 2009-03-20T19:41:52.307 回答
0

~ 在 Perl 中不会自动扩展。

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

opendir my $fh, glob('~/') and die( "Thats right!" );
于 2009-01-12T00:33:33.107 回答
0

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

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

如果您不进行defined()测试,如果找到名为“0”的文件,循环将终止。

于 2009-01-12T00:42:31.123 回答
0

您是否在CPAN上查看过日志解析器?我用“log parse”搜索,结果超过 200 次。有些(可能很多)不相关——有些可能是相关的。这部分取决于您使用的 Web 服务器。

于 2009-01-12T01:07:59.980 回答
0

我读对了吗?给你错误的第 10 行是

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

根据第 6 行,您尝试读取的 $file,

@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
  }
}

请注意,这不涉及子目录。

于 2009-01-12T01:17:47.840 回答
0

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

perl -wnl -e '/12.211.23.200/ 并打印;' *.log > 输出.txt

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

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

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

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

于 2013-02-13T15:22:07.570 回答
-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/;

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

于 2009-01-12T08:58:56.050 回答