使哈希识别Perl中的唯一数据

时间:2013-12-13 20:54:54

标签: perl hash tcpdump

我正在研究计算机编程最终的介绍,我正在使用Perl进行编码。

我正在尝试使用哈希来过滤IP地址列表,并将所有唯一的地址推送到数组中。

出于某种原因,它只持有两个IP中的一个。

my @broken_data;
my @source_ip;
my @source_ip_mod;
my @destin_ip;
my @destin_ip_mod;
my $file_input;
my $file_output;
my $countline = 0;    # set counter to 0
my $countuser = 0;
my $countpass = 0;

# Command to open the source file for use. Gives user the option of what file to look at.
print "Please enter a file name for diagnosis. \n";
$file_input = <STDIN>;    # file name input
chomp $file_input;
open SF, $file_input or die "Couldn't open Source File: $!\n";    # open the users file

# allows the user to name the File Output
print "Please enter a file name for the summary output. \n";
$file_output = <STDIN>;                          # collects name
chomp $file_output;                              # chomps the input
open(SFO, ">$file_output") or die "Couldn't create $file_output. \n"; # creates a file in current directory for output

while (<SF>) {    # while SF is open
  $countline++;    # counts each line

  if ($_ =~ /USER/i) {
    $countuser++;
  }

  if ($_ =~ /PASS/i) {
    $countpass++;
  }

  chomp($_);

  if ($_ =~ /^22:28/) { # look for any instence of  22:28, ^ to match with the beginning of string

    @broken_data = split(' ', $_);   # takes the data and splits it at the space
    print "$broken_data[0], $broken_data[2], $broken_data[4], $broken_data[-1]\n";    # takes out each element that i need to work with

    print "\tTime: $broken_data[0]\n";    # Prints the time portion of the array

    @source_ip = split('\.', $broken_data[2]);     # splits the source ip at the period

    print "\tSource IP: $source_ip[0].$source_ip[1].$source_ip[2].$source_ip[3] Port: $source_ip[-1]\n"; # Prints the Source  IP

    @destin_ip = split('\.', $broken_data[4]);   # splits the destination ip at the period
    @destin_ip_mod = split(':', $destin_ip[4]);  # cuts off the trailing semi-colon
    $destin_ip[4] = $destin_ip_mod[0];

    print "\tDestination IP: $destin_ip[0].$destin_ip[1].$destin_ip[2].$destin_ip[3] Port: $destin_ip[4]\n";

    print "\tPacket size: $broken_data[-1].\n";
  }
}

my @unique_source_ip;    # creates an array for the unique source ips
my %seen_source_ip;      # hash to sort the data
foreach $_ (@broken_data[2]) {    # foreach loop, setting the Source IP to the default scalar
  if (!$seen_source_ip{$_}) {     # if the source IP has not been seen, put it into the default scalar
    push(@unique_source_ip, $_);  # push the default varriable into the unique source ip array
    $seen_source_ip{$_} = 1;
  }
}

my $unique_source_cnt = @unique_source_ip;

1 个答案:

答案 0 :(得分:2)

我能做的最好的事情就是告诉你如何编写相同的代码。我不是说这将是我的解决方案,因为我无法准确理解你在做什么,但我希望你能看到有更好的方法来编写软件。

最大的区别是

    程序开始时的
  • use strictuse warnings。您应该使用您编写的每个程序执行此操作,无论多小。没有use strict,用my声明任何变量是没有意义的,因为Perl只会在任何地方使用包变量。

  • 正确缩进代码,只有在编写非常复杂的内容时才写注释。当您添加评论时,永远不要说代码正在做什么 - 代码本身就是这样做的。相反,说为什么它正在做它。大多数情况下,您的代码应该是不言自明的。

  • 不要在顶部的块中声明所有变量。你可能也不会像我说的那样费心。这通常是程序员使用C语言的遗产,重要的是要记住Perl和C之间几乎没有任何相似之处。

  • 使用open和词法文件句柄的三参数形式。在$!字符串中加入die的值,以便您知道为什么打开失败。

问题可能在你的原始行

foreach $_ (@broken_data[2]) { 

执行循环一次,将$_设置为$broken_data[2]的值。每次执行@broken_data读取循环时都会覆盖数组while,因此当您点击for时,您正在查看 last 行中的数据读。我不知道你的意图,但我确信这是不对的。

use strict;
use warnings;

print "Please enter a file name for diagnosis: ";
my $input_fname = <STDIN>;
chomp $input_fname;
open my $in, '<', $input_fname or die "Couldn't open '$input_fname': $!";

print "Please enter a file name for the summary output: ";
my $output_fname = <STDIN>;
chomp $output_fname;
open my $out, '>', $output_fname or die "Couldn't create '$output_fname': $!";

my $n = 0;
my @broken_data;
my ($countuser, $countpass) = (0, 0);

while (<$in>) {
  chomp;
  ++$n;

  ++$countuser if /USER/i;
  ++$countpass if /PASS/i;

  next unless /^22:28/;

  @broken_data = split;
  print join(', ', @broken_data[0, 2, 4, -1]), "\n";

  print "\tTime: $broken_data[0]\n";

  my @source_ip = split /\./, $broken_data[2];

  print "\tSource IP: ", join('.', @source_ip[0,1,2,3,-1]), "\n";

  my @destin_ip     = split /\./, $broken_data[4];
  my @destin_ip_mod = split /:/, $destin_ip[4];
  $destin_ip[4]     = $destin_ip_mod[0];

  print "\tDestination IP: ", join('.', @destin_ip[0..4]), "\n";

  print "\tPacket size: $broken_data[-1].\n";
}

my @unique_source_ip;
my %seen_source_ip;
for ($broken_data[2]) {
  unless ($seen_source_ip{$_}) {
    push(@unique_source_ip, $_);
    $seen_source_ip{$_} = 1;
  }
}

my $unique_source_cnt = @unique_source_ip;