The simplest seems to be to put your $recordcnt
in the key itself like this $record_id = $recordcnt.'_'.$time[1]."_".$time[2];
and make sure that it never gets zeroed inside the loop (you have a line that does $recordcnt=0`, this is wrong). Also I didn't find any place where you actually increment the recordcnt.
However, it seems to me that you'd be much better off by using an array of hashes instead of a simple hash. The array will be ordered the same as your input file but you can use sort
to sort it any way and you don't get messed up with strange counters and such. It's not too hard to rewrite it with an array.
First, create the array that will hold all your data in the beginning of your script (let's call it @myarray
).
Before your loop starts, create a hash ref (reference to a hash, easier to handle) which will contain one object.
my $tmphash = {};
while (<IN>) {
......
Now replace your $hash{$record_id}{$recordcnt}
with just $tmphash->
(e.g.
if ($peer_ip) {$hash{$record_id}{$recordcnt}{'peer_ip'} = $peer_ip;}
will now be
if ($peer_ip) {$tmphash->{'peer_ip'} = $peer_ip;}
and so on)
When you know that you have gathered the whole object in the tmphash
, just push the tmphash
in the array, reinitialize the tmphash and continue with the next object.
push @myarray, $tmphash;
$tmphash = {};
All done! Now all you need to do is loop through the array to print your data
foreach my $row (@myarray) {
print "\t $row->{'peer_ip'}\n";
#... and so on
EDIT
I took the liberty of fixing your script. There where small errors and a major logical error. I didn't delete anything of your code, but I commented out some lines and added some of my own. All lines that I changed or added are marked with a #~#~
in the end of the line so you can easily track them and see the differences.
#!/usr/bin/perl -w
use strict;
use warnings;
my @datasetarray;
my $Dir = "/root/updates/processed/";
my $exit = 0;
opendir(DIRECTORY, $Dir) or die $!;
while (my $file = readdir(DIRECTORY)) {
unless ($file=~/\.hr$/){next;}
#unless ($file=~/\.txt$/){next;}
my $file = $Dir."/".$file;
print "$file\n";
open (IN, $file) or die "error reading file: ", $file,"\n";
my $record_id = "";
my $type = "";
my $peer_ip = "";
my $peer_as = "";
my $local_ip = "";
my $local_as = "";
my $next_hop = "";
my @nodes_and_index = ();
my @withdraw_prefix = ();
my @announce_prefix = ();
my $tmphash = {};
while (<IN>) {
#$exit++; last if ($exit==5);
if (/^TIME/) {
if ($type) {$tmphash->{'type'} = $type;}
if ($peer_ip) {$tmphash->{'peer_ip'} = $peer_ip;}
if ($peer_as) {$tmphash->{'peer_as'} = $peer_as;}
if ($local_ip) {$tmphash->{'local_ip'} = $local_ip;}
if ($local_as) {$tmphash->{'local_as'} = $local_as;}
if ($next_hop) {$tmphash->{'next_hop'} = $next_hop;}
if (@nodes_and_index) {push @{$tmphash->{'nodes_and_index'}}, @nodes_and_index;} #~#~
if (@withdraw_prefix) {push @{$tmphash->{'withdraw_prefix'}}, @withdraw_prefix;} #~#~
if (@announce_prefix) {push @{$tmphash->{'announce_prefix'}}, @announce_prefix;} #~#~
if ($record_id) { #~#~
$tmphash->{'time'} = $record_id; #~#~
push @datasetarray, $tmphash;#~#~
$tmphash = {};#~#~
} #~#~
#The three commented lines above provide error, thus i don't know if i am implementing it the right way, since they are array and different from the others.
$peer_as = "";
$peer_ip = "";
$type = "";
$local_ip = "";
$local_as = "";
$next_hop = "";
$record_id = "";
@nodes_and_index = ();
@withdraw_prefix = ();
@announce_prefix = ();
my @time = split '\s', $_;
$record_id = $time[1]."_".$time[2];
} elsif (/^TYPE/) {
my @type_tmp = split '\s', $_;
$type = $type_tmp[1];
} elsif (/^FROM/) {
my @from_tmp = split '\s', $_;
$peer_ip = $from_tmp[1];
$peer_as = $from_tmp[2];
$peer_as =~ s/AS//;
} elsif (/^TO/) {
my @to_tmp = split '\s', $_;
$local_ip = $to_tmp[1];
$local_as = $to_tmp[2];
$local_as =~ s/AS//;
} elsif (/^ASPATH/) {
my @nodes_tmp = split '\s', $_;
shift @nodes_tmp;
my $index = 0;
foreach my $node (@nodes_tmp) {
$index++;
push @nodes_and_index, ($node , $index);
}
}elsif (/^NEXT_HOP/) {
my @next_hop_tmp = split '\s', $_;
$next_hop = $next_hop_tmp[1];
}elsif (/^WITHDRAW/) {
while (<IN>) {
last if !/^ +/;
push @withdraw_prefix, $_ ;
}
}elsif (/^ANNOUNCE/) {
while (<IN>) {
last if !/^ +/;
push @announce_prefix, $_;
}
}
#if ($record_id) { # handle last result #~#~
# push @datasetarray, $tmphash;#~#~
# $tmphash = {};#~#~
# }#~#~
}
close IN;
#insert the last element of the file
if ($type) {$tmphash->{'type'} = $type;} #~#~
if ($peer_ip) {$tmphash->{'peer_ip'} = $peer_ip;} #~#~
if ($peer_as) {$tmphash->{'peer_as'} = $peer_as;} #~#~
if ($local_ip) {$tmphash->{'local_ip'} = $local_ip;} #~#~
if ($local_as) {$tmphash->{'local_as'} = $local_as;} #~#~
if ($next_hop) {$tmphash->{'next_hop'} = $next_hop;} #~#~
if (@nodes_and_index) {push @{$tmphash->{'nodes_and_index'}}, @nodes_and_index;} #~#~
if (@withdraw_prefix) {push @{$tmphash->{'withdraw_prefix'}}, @withdraw_prefix;} #~#~
if (@announce_prefix) {push @{$tmphash->{'announce_prefix'}}, @announce_prefix;} #~#~
if ($record_id) { #~#~
$tmphash->{'time'} = $record_id; #~#~
push @datasetarray, $tmphash;#~#~
$tmphash = {};#~#~
} #~#~
}
foreach my $row (@datasetarray) {
#print $_, "\n"; #Time doesn't get printed #~#~
print "\t $row->{'time'}\n"; #~#~
print "\t $row->{'peer_ip'}\n"; #OK
print "\t $row->{'peer_as'}\n"; #OK
print "\t $row->{'local_ip'}\n"; #OK
print "\t $row->{'local_as'}\n"; #OK
print "\t $row->{'next_hop'}\n"; #OK
#you can print array refs like this, just make a check that they are declared
print "\t @{$row->{'nodes_and_index'}}\n" if ref $row->{'nodes_and_index'} eq 'ARRAY';#~#~
print "\t @{$row->{'withdraw_prefix'}}\n" if ref $row->{'withdraw_prefix'} eq 'ARRAY';#~#~
print "\t @{$row->{'withdraw_prefix'}}\n" if ref $row->{'withdraw_prefix'} eq 'ARRAY';#~#~
}