-2

I'm working on a introduction to computer programming final, and I'm coding in Perl.

I'm trying to use a hash to filter a list of IP addresses and push all the unique ones onto an array.

For some reason it's only holding one of the two IPs.

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;
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • 5
    Welcome to StackOverflow. Can you narrow down the problem any? Maybe to a particular few lines line? You may find this a good read: http://sscce.org/. – jpmc26 Dec 13 '13 at 21:00
  • You are unlikely to get help by posting that much code. I would suggest that you remove all irrelevant code (e.g. most or all of the print statements). – The Guy with The Hat Dec 13 '13 at 21:19
  • Sorry i wasn't sure what people would want to see, i'll cut it back though thanks – user3100825 Dec 13 '13 at 21:40
  • You should also include sample input, or the loop where you are reading from a file. – simbabque Dec 13 '13 at 21:49
  • 2
    Re "i wasn't sure what people would want to see", Ideally, we'd like to see a minimal, runnable demonstration of the problem. Honestly, you should already have done that as part of debugging. – ikegami Dec 13 '13 at 21:53
  • I just took that off because of the last comment, I'll add it back though. – user3100825 Dec 13 '13 at 21:53
  • Re "We'd like to see a minimal, runnable demonstration of the problem." Well what I had up before was the program that ran, just didn't properly record the IP adresses. I think it's because @broken_data is being overwritten each time your /^22:28/ regex matches. So, when the while loop completes, that array will only contain 1 row of data. – user3100825 Dec 13 '13 at 21:59
  • 1
    What you had up wasn't minimal (by far), and didn't demonstrate the problem (prompted for a file that wasn't provided). What you have up still isn't, and doesn't demonstrate the problem either (just runs with no output). Your question purports to be about hashes, but the first appearance of a hash is on the second screen of what you posted (45 lines down). – ikegami Dec 13 '13 at 22:04
  • alright I added the beginning of the program so it is now runs and prompts for input. Where can I upload the source .txt file? – user3100825 Dec 13 '13 at 22:07
  • 1
    I don't think it's so much the *quantity* of your code as the *quality*. I've reformatted it so that the indentation is correct and it's much more readable. You also have *far* too many comments. I can't see any comment in there that is useful. Have you been taught to comment your code this way? As it is, the comments just make noise that make it difficult to read the program. – Borodin Dec 13 '13 at 22:24
  • Ya I actually lost points on my last project for not commenting enough. I know it seems redundant, but I would rather over comment than under comment. – user3100825 Dec 13 '13 at 22:28
  • There's a big difference between quantity of comments vs. quality of comments. – ThisSuitIsBlackNot Dec 13 '13 at 22:41
  • 1
    Where are you studying? The encouragement to comment programs is *very* old-fashioned, and comes from the days of Fortran when it was pretty much impossible to write code that explained itself. Things are very different now, and a responsible professor has no business marking you down for insufficient comments. The best you can do is to comment your code if you have to to get through your course, but then stop doing it and write clear code instead once you graduate. Remember that I had to *take your comments out* so that I could understand your code! – Borodin Dec 13 '13 at 22:54
  • Re "Where can I upload the source .txt file?" What makes you think you need a file to demonstrate your problem!? – ikegami Dec 14 '13 at 02:29

1 Answers1

2

The best I can do is to show you how I would write the same code. I am not saying this would be my solution, as I can't understand exactly what it is you're doing, but I hope you can see that there is a better way to write software.

The biggest differences are

  • use strict and use warnings at the start of the program. You should do this with every program you write, no matter how small. Without use strict there is no point in declaring any of your variables with my, as Perl will just use package variables everywhere.

  • Indent your code properly, and write comments only when you are writing something very complex. When you do add a comment, never say what the code is doing - the code itself does that. Instead, say why it is doing it. Most of the time your code should be self-explanatory.

  • Don't declare all your variables in a block at the top. You may as well not bother at all as I have said. This is usually a legacy of a programmer's experience with C, and it is important to remember that there is almost nothing similar between Perl and C.

  • Use the three-parameter form of open and lexical file handles. Incorprate the value of $! in the die string so that you know why the open failed.

The problem is probably in your original line

foreach $_ (@broken_data[2]) { 

which executes the loop just once, setting $_ to the value of $broken_data[2]. The array @broken_data is overwritten on each execution of the while read loop, so when you hit the for you're looking at the data from the last line read. I can't tell what you intended but I'm sure that isn't right.

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;
Borodin
  • 126,100
  • 9
  • 70
  • 144