为什么我的变量重置为零 - perl

时间:2013-12-10 23:28:35

标签: regex perl

有人能告诉我为什么其他一切都有效,除了我的USER和PASS计数器变量在我''while'循环的底部?当他们为用户输出3和为传递输出2时,某些东西会将它们重置为零。

(代码是计算USER和PASS一词的实例数。)

如果您发现任何其他草率错误,请告诉我们!提前谢谢!!

输入文件的第一行(注意:此格式重复2006行,只有数字更改)

22:28:31.819551 IP 98.114.205.102.1924 > 192.150.11.111.1957: Flags [P.], seq 1:124, ack 2, win 64239, length 123E...<.@.q...br.f...o....\.bfP....Y..echo USER 1 get ssms.exe 

代码:

use strict;
use warnings;
use diagnostics;

open MYFILE, '<', 'source_file.txt' or die $!;
open OUT, '>', 'Summary_Report.txt' or die $!;
open OUTFILE, '>', 'Header.txt' or die $!;

my $start_time = undef;
my $end_time;
my $user = 0;
my $pass = 0;
my $linenum = 0;

while (<MYFILE>) {              # loops through every line in file
    chomp;                      # break new line
    $linenum++;                 # count line 1 to end of file, 2006
    if (/^\d+:\d+/) {
        my @header = split (/\s+/, $_);
        print OUTFILE "$linenum: @header\n\n";
        if (/^22:28/ && !defined($start_time)) {
            $start_time = $header[0];
        }
        if (/22:28/) {
            $end_time = $header[0];
        }
        $user++ if /USER/ig;
        $pass++ if /PASS/ig;
    }
}

print OUT "Total # of times phrases were used:\n\n
   USER (variations thereof) = $user\n\n
   PASS (variations thereof) = $pass\n\n\n";

好的大家,这是我的代码的最后一点。 (输出尚未完成,这就是为什么有些仍然没有答案,但你可以了解我正在做什么以及需要做什么。

#!/usr/bin/perl -w

# Final project
use strict;
use warnings;
use diagnostics;

#opens txt file: read mode
open MYFILE, '<', 'source_file.txt' or die $!;

#opens output txt file: write mode
open OUT, '>', 'Summary_Report.txt' or die $!;

#open output txt file: write mode
#used to store header 'split' info
open OUTFILE, '>', 'Header.txt' or die $!;

my $i = 0;
$| = 1; #disable output buffering

my $start_time = undef; #undefined to avoid recycling through other time stamps
my $end_time;

my $user = 0;
my $pass = 0;

my $packet_size = 0; #goes with length#

my @header;

my @source_ip;
my @source_port;
my $src_port;
my @src_port;

my @dest_ip;
my @dest_port;
my $destination_port;
my @destination_port;


while (<MYFILE>) { #loops through every line in file
    chomp; #break new line

    if (/^\d+:\d+/) {

    #separate pieces of information from TCPDUMP into list
    @header = split (/\s+/, $_);
    print OUTFILE "$.: @header\n\n";

##############################T I M E##################################

    #defining first 'line & time' as 'special'
    if (/^22:28/ && !defined($start_time)) {
        $start_time = $header[0];
        #print "$start_time\n"; ###used as a check###
    }   

    #Used recycling of time stamps to find last one available
    if (/22:28/) {
        $end_time = $header[0];
    }       

#############################S O U R C E#################################

    #categorizing each section of ip's from source
    @source_ip = split ('\.', $header[2]);

    #adding ip's together, joining in concatenation by '.'
    $source_ip[$i] = $source_ip[0] . '.' . $source_ip[1] . '.' . $source_ip[2] . '.' .      $source_ip[3];
    #print $source_ip[$i]; (check)

    @source_port = split (':', $source_ip[4]);
    $src_port[$i] = $source_port[0];

#########################D E S T I N A T I O N###########################

    #categorizing each section of ip's from destination
    @dest_ip = split ('\.', $header[4]);

    #adding ip's together, joining in concatenation by '.'
    $dest_ip[$i] = $dest_ip[0] . '.' . $dest_ip[1] . '.' . $dest_ip[2] . '.' . $dest_ip[3];
    #print $dest_ip[$i]; (check)

    @dest_port = split (':', $source_ip[4]);
    $destination_port[$i] = $dest_port[0];

#############################L E N G T H#################################

    #-1 represents length
    $packet_size = $packet_size + $header[-1];
    #print $packet_size; (check)

    $i++
    }
}

close MYFILE;

#########################D A T A S E C T I O N###########################

open MYFILE, '<', 'source_file.txt' or die $!;

#I am separating loop to reset values#
while (<MYFILE>) { 

    #finds all instances of USER
    $user++ if /USER/ig;
    #print "user" (use as check)

    #finds all instances of PASS
    $pass++ if /PASS/ig;
    #print "pass" (use as check)

}

#Output summary to new file: overwrite file
print OUT "SUMMARY REPORT:\n\n";

print OUT "# of total lines in the file = $.\n\n\n";

print OUT "Range of time the file encompasses:\n\n
    Starting Time = $start_time\n\n
    Ending Time = $end_time\n\n
    Total Time = 16.219218\n\n\n";

print OUT "Total # of distinct SOURCE ip addresses = \n\n\n";

print OUT "Total # of distinct DESTINATION ip addresses = \n\n\n";

print OUT "Listing of distinct SOURCE ip addresses = \n\n\n";

print OUT "Listing of distinct DESTINATION ip addresses = \n\n\n";

print OUT "Total # of distinct SOURCE TCP ports = \n\n\n";

print OUT "Total # of distinct  DESTINATION TCP ports = \n\n\n";

print OUT "Listing of distinct SOURCE TCP ports = \n\n\n";

print OUT "Listing of distinct DESTINATION TCP ports = \n\n\n";

print OUT "Total # of times phrases were used:\n\n
    USER (variations thereof) = $user\n\n
    PASS (variations thereof) = $pass\n\n\n";

print OUT "DETAIL SECTION:\n\n\n";

print OUT "SOURCE IP address activity by port over time:\n\n
    Mean packet size for above = \n\n
    Median packet size for above = \n\n\n";

print OUT "Detail IP address activity by port over time:\n\n
    Mean packet size for above = \n\n
    Median packet size for above = \n\n\n";

print OUT "Any and all interesting text w/in the DATA section of the file:\n\n";
close OUT;              #
close OUTFILE;          #close remaining files
close MYFILE;           #

1 个答案:

答案 0 :(得分:2)

只是一些观察。也许这会有所帮助:

让我们看看你的循环:

while (<MYFILE>) {                                 # 1
    chomp;                                         # 2
    if (/^\d+:\d+/) {                              # 3
        my @header = split (/\s+/, $_);            # 4
        print OUTFILE "$linenum: @header\n\n";     # 5
        if (/^22:28/ && !defined($start_time)) {   # 6
            $start_time = $header[0];              # 7
        }
        if (/22:28/) {                             # 8
            $end_time = $header[0];                # 9
        }
        $user++ if /USER/ig;                       # 10
        $pass++ if /PASS/ig;                       # 11
    }
}

您意识到$user++$pass++位于if语句(第3行)中。它看起来应该可以工作,因为所有的行都匹配正则表达式。第5行打印到Header.txt。你在Header.txt得到任何输出吗?如果没有,您在第3行的if声明中出现了问题。

如果您要在Header.txt中获得输出,我们可以使用grepwc来计算我们获得USERPASS的次数:< / p>

$ grep /USER/i Header.txt | wc -l   # The total you should get for $user
$ grep /PASS/i Header.txt | wc -l   # The total you should get for $pass

如果它们都为零,我们知道您找不到会增加$user$pass的行。

我注意到的另一件事是你在整个地方使用默认变量$_。这可能会导致问题,因为$_的值可能会被替换为您。我手边没有看到任何东西,但是当你到达第10行和第11行时,$_可能没有设置为你读到的行。

你几乎应该总是使用一个词法范围的局部变量 - 特别是对于包含不止几行的循环:

while ( my $line = <MYFILE> ) {
    chomp $line;
    if ( $line =~ /^\d=:\d+/ ) {
    ....
    if ( $line =~ /USER/i ) {
       $user += 1;
    }
    if ( $line =~ /PASS/i ) {
       $pass += 1;
    }
}

这本身可以解决您的问题 - 特别是如果您缩短了循环以发布您认为相关的信息。其他评论者已经尝试了您的单行输入并报告您的代码适用于他们。可能是您可能正在做一些事情来改变$_的值并且没有将它放在您的编码样本中。

请注意,我使用的是预先固定的if而不是固定后的if。它使代码更清晰,因为有人扫描您的代码可能会错过帖子固定if. Also, it makes it clearer that a single line may be counted twice if they both contain USER and PASS`。这有可能发生吗?

虽然排名#6#9对我来说有点奇怪。如果开始时间不是晚上10:28怎么办?为什么$start_time$end_time似乎都在看同一件事?结束时间是否有一些事情发生,因为我注意到第8行没有第6行的那个起始线锚。

为什么不简单地将第一行读入,$start_time,以及$end_time中读取的最后一行?

另外,你做split,但你似乎没有对数据做任何事情(第一部分除外)。执行substr以提取所需数据可能更有效:

my $time_stamp = substr( $line, 0, 15 );

这样,很明显你只需要行的第一部分作为时间戳,而你并不关心行的其余部分。正在查看代码的用户不会想知道您打算如何处理这些数据。另外,你可以使用一个很有意义的名字。啊!这是一个$time_stamp,而不是一些毫无意义的$header[0]。此外,使用substr,您可以将值从22:28:31.819551减少到仅22:28:31

my $time_stamp = substr( $line, 0, 8 );

同样,我没有看到任何错误。我已经尝试根据你的行生成一堆数据并通过你的代码运行它们,但你所拥有的似乎工作。这个循环比你发布的更长吗?


附录

有几件事。您正在程序的最开始使用my 定义变量,就像您在COBOL或Pascal中编写一样。 my的优点是允许变量范围。使用my定义的变量是词法范围的。也就是说,它只存在于它创建的块中。这可以帮助您发现错误。

不要在程序开头定义所有变量。定义它们以利用范围机制。例如,我们来看@header。这仅用于循环。在那里定义:

while (my $line = <MYFILE>) { # Don't use `$_`. Use a real variable!
chomp $line; #break new line
 my @header = split /\s+/, $line;  # Define @header here!

if ( $line =~ /^\d+:\d+/ ) {
    print OUTFILE "$.: $line\n\n"; # {rint $line instead of gluing @header back together

每次进行循环时,@header将再次变为未定义。对于您正在解析的下一行,请保持纯净和干净。这样,您就不必担心@header中的先前值会妨碍您。

此外,你的循环现在足够长,$_可能会让你陷入困境。使用词汇范围的真实变量(就像我对$line所做的那样。$line包含的内容很明显。$_可能并不总是很明显 - 甚至对你来说也是如此。< / p>

另外,请看一下这一行:

@dest_ip = split ('\.', $header[4]);
$dest_ip[$i] = $dest_ip[0] . '.' . $dest_ip[1] . '.' . $dest_ip[2] . '.' . $dest_ip[3];

如果我正确地阅读它,你有一个变量$i,你正在递增,你正在解析的每一行正在发生什么。但是,你每次都要覆盖@dest_ip

你为什么这样做?你想做什么?您将IP拆分为四个组,将它们重新组合在$dest_ip[$line_number]中,然后用您的拆分销毁@dest_ip

您应该考虑使用Perl模块,因为您正在解析Apache httpd日志(我相信它是一个Apache httpd日志)。看看Apache::LogRegex,看看它是否可以减轻你为获得所需数据所做的大部分解析。