1
votes

I have two hashes and I want to iterate over the first hashes keys once (tcp, tls, dns) and then find the matching key in the second hash. From there I want to compare the values in each hash for tcp.

At the moment when I attempt to do this, it seems to match on every key in the second hash. TCP may be selected from the first hash but where I have if ($key1 == $key2), it will match multiple times even though the keys do not match each other. It may be me not having a proper understanding of each.

#!/usr/bin/perl

open my $fh, "newlogs.txt" or die $!;
my %line_1 = split ' ', <$fh>;
my %line_2 = split ' ', <$fh>;

while (my($key1, $value1) = each %line_1) {
        while (my($key2, $value2) = each %line_2) {
                if ($key1 == $key2) {
                        print "$key1 $key2\n";
                }
        }
}

newlog.txt:

tcp 217837 tls 138531 http 50302 udp 37852 dns 23625 ldap 14160 krb5 8828 smb 2148 ssh 549 ftp 219 smtp 161 icmp 6 rdp 3 ssdp 3
tcp 198650 tls 125770 http 44260 udp 37610 dns 23827 ldap 13904 krb5 8805 smb 2128 ssh 629 ftp 219 smtp 156 icmp 5 ssdp 1

I'd hope to achieve something like this for the output which shows the difference in both tcp values, but for every protocol (key). tcp=19187

EDIT:

I've found a solution here: Comparing two hashes with the keys and values

Solution:

#!/usr/bin/perl

open my $fh, "newlogs.txt" or die $!;
my %line_1 = split ' ', <$fh>;
my %line_2 = split ' ', <$fh>;

for (keys %line_1) {
        unless (exists $line_2{$_} ){
                print "$_: not found in second hash\n";
                next;
        }
        if ($line_1{$_} eq $line_2{$_} ) {
                print "$_: no change \n";
        }
        else {
                #print "$_: values are not equal\n";
                my $result = $line_1{$_} - $line_2{$_};
                print "$result\n";
        }
}
1
I want to split it on spaces so that part is fine, the hashes are built fine. Just need to operate on them now. - temp44
What's your desired result given your input lines? - Sobrique
The "EDIT" seems to do what you described -- is there anything missing? If this is indeed a good solution it may be better to post that part as an answer (you may post answers to your own questions and this is a good idea when you find a solution). One thing though: if you indeed want to print when keys mismatch (the unless block) then you are missing cases when a key in %line_2 is not in %line_1. But it seems that you rather don't care about that and may do away with unless block.) - zdim
The each indeed can be a little tricky ... but I am not sure what is wrong there, your attempt is reasonable. - zdim
Please always have use warnings; and use strict; at the beginning. It really helps a lot. - zdim

1 Answers

1
votes

Turn on use strict; use warnings;.

It will tell you:

Argument "ssdp" isn't numeric in numeric eq (==) at line 10

This is a hint that you should be using eq

But more fundamentally, nesting an each for two hashes is entirely redundant, as the point of a hash is a direct lookup.

How about:

foreach my $key ( keys %line_1 ) {
   if ( $line_2{$key} ) { 
       print "Match found for $key\n";
       if ( $line_1{$key} ne $line_2{$key} ) { 
           print "$key $line_1{$key} doesn't match $line_2{$key}\n";
       }
   }
   else { 
     print "No key $key found in line 2\n";
   } 
}

(and if relevant, reverse the logic so you check all the keys in line_2 as well, to check they're not missing from line1)