Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Regex matching part of one hash key to another

by KevinNC (Initiate)
on Jan 06, 2011 at 23:02 UTC ( [id://880962]=perlquestion: print w/replies, xml ) Need Help??

KevinNC has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I'm new to perl and to this site (it has been an HUGE help) and I'm having a problem I am hoping someone can assist me with solving. Basically I am trying to prevent a lengthy manual process of searching the OUI of a routers ARP cache to find the Company. We have tools but no access so I'm stuck with finding a faster way. The problem I'm having is I can match the first iteration of the ARP cache hash but afterwards it stops matching altogether and just iterates the rest with blank results. Below is the code I have so far, please be kind as I am still learning, a small arp cache file and the resulting output :) Thanks in advance for any and all assistance.

use 5.010; use strict; use warnings; # filehandle section open STDOUT, ">ouiresults.txt"; # Output file after program is ru +n. open STDERR, ">errlog.txt"; # Error Log. my $f1 = 'oui.txt'; # Filehandle of the OUI list from + the IETF used to create a hash of oui and company. my @data = (); # Declared Array to be created +with the input file for searching the MAC address. my %hash = (); # Declared Hash to be created w +ith the input file to store the IP to MAC mappings. my %oui = (); # Delcared Hash containing the O +UI to Company mapping. open (LIST1, $f1) || die "File not found\n"; # Takes the oui +file and creates a hash while (<LIST1>) { # Key is OUI chomp; # Value is Company if (/[\x20]{5}\(base 16\)[\t]{2}/) { $oui{$`} = $'; } } close LIST1; open(INPUT, $ARGV[0]) || die "Cannot do eet! $!"; # Takes the inp +ut file name on the command line and builds an array. while (<INPUT>) { # This is the ARP + Cache file created from a copy/paste of a routers push @data, "$_"; # show arp comm +and. } close(INPUT); for (@data) { # This section iterates over the ARP cache array and + pulls the IP and MAC address out and stores it into a hash if ($_ =~ m/([\d]+\.[\d]+\.[\d]+\.[\d]+).*([\w]{4})\.([\w]{4})\.([\w +]{4})/i) { # Key is MAC my $temp = $2.$3.$4; + # Value is IP $hash{$temp} = $1; } } while ( my ( $key, $value ) = each %hash ) { my $match = substr $key, 0, 6; say "$hash{$key} mapped to $key for company $oui{$match}!"; }

this is the input file tech.txt (IP and MAC addresses changed to protect my job) :D

Internet 10.10.10.1 - 000b.462d.2846 ARPA FastEthernet0

Internet 10.10.10.2 1 0013.2004.acde ARPA FastEthernet0

Internet 10.10.10.3 7 0800.4ec8.94ac ARPA FastEthernet0

This is the reulting output

10.10.10.2 mapped to 00132004acde for company Intel Corporate!

10.10.10.3 mapped to 08004ec894ac for company !

10.10.10.1 mapped to 000b462d2846 for company !

As you can see I can only get the first iteration to match and can only seem to get it using subtr, afterwards it just stops. I can iterate through the hash just fine and print it out, seems from the examples I've found it should work.

I have tried various other ways but thats the furthest I have been able to get so far as most of the time I dont get any matches on the Company name.

Also, I wasn't sure how to get the oui.txt up in the post for testing as it's a pretty big file. Thanks again. :)

Replies are listed 'Best First'.
Re: Regex matching part of one hash key to another
by jwkrahn (Abbot) on Jan 07, 2011 at 00:07 UTC
    if (/[\x20]{5}\(base 16\)[\t]{2}/) { ... if ($_ =~ m/([\d]+\.[\d]+\.[\d]+\.[\d]+).*([\w]{4})\.([\w]{4})\.([\w +]{4})/i) {

    Why put a character class inside a character class?

    if (/\x20{5}\(base 16\)\t{2}/) { ... if ($_ =~ m/(\d+\.\d+\.\d+\.\d+).*(\w{4})\.(\w{4})\.(\w{4})/i) {

    And why use the /i option on a pattern that contains NO literal alphabetic characters?



    open(INPUT, $ARGV[0]) || die "Cannot do eet! $!"; # Takes the inp +ut file name on the command line and builds an array. while (<INPUT>) { # This is the ARP + Cache file created from a copy/paste of a routers push @data, "$_"; # show arp comm +and. } close(INPUT); for (@data) { # This section iterates over the ARP cache array and + pulls the IP and MAC address out and stores it into a hash if ($_ =~ m/([\d]+\.[\d]+\.[\d]+\.[\d]+).*([\w]{4})\.([\w]{4})\.([\w +]{4})/i) { # Key is MAC my $temp = $2.$3.$4; + # Value is IP $hash{$temp} = $1; } }

    What is the point of  @data?    Why not just populate  %hash from inside the while loop?    And why copy  $_ to a string before pushing it into  @data?



      Thanks for the tips. I am a very beginning perl user, I picked up the Llama book a month ago and have been with it off and on since. This is not my primary job function, I'm more of a NOC person but there was some free time and was given the go ahead to try and pick up some coding again to help reduce some manual processes, so most of the stuff is adaptations from the books examples and my, VERY, limited knowledge. It has been 18 years since I have written any code in school as an elective class. I'm hoping to use this more and more and become more effecient and these tips help out a lot. I have cleaned up the code based on the suggestions and have reposted here. Most of the time I use the explicits to help learn what is going on and make it clear to my n00b eyes :).

      use 5.010; use strict; use warnings; # filehandle section open STDOUT, ">ouiresults.txt"; # Output file after program is ru +n. open STDERR, ">errlog.txt"; # Error Log. my $f1 = 'oui.txt'; # Filehandle of the OUI list from + the IETF used to create a hash of oui and company. my %hash = (); # Declared Hash to be created w +ith the input file to store the IP to MAC mappings. my %oui = (); # Delcared Hash containing the O +UI to Company mapping. open (LIST1, $f1) || die "File not found\n"; # Takes the oui +file and creates a hash while (<LIST1>) { # Key is OUI chomp; # Value is Company if (/\x20{5}\(base 16\)\t{2}/) { $oui{$`} = $'; } } close LIST1; open(INPUT, $ARGV[0]) || die "Cannot do eet! $!"; # Takes the inp +ut file name on the command line and builds a hash. while (<INPUT>) { # This is the ARP + Cache file created from a copy/paste of a Cisco routers arp cache if ($_ =~ m/(\d+\.\d+\.\d+\.\d+).*(\w{4})\.(\w{4})\.(\w{4})/) { + # Key is MAC my $temp = $2.$3.$4; + # Value is IP $hash{$temp} = $1; } } close(INPUT); while ( my ( $key, $value ) = each %hash ) { my $match = substr $key, 0, 6; say "$hash{$key} mapped to $key for company $oui{$match}!"; }

      OUTPUT

      10.147.23.11 mapped to 001320048fef for company Intel Corporate!

      10.147.23.4 mapped to 08004ec802b4 for company !

      10.147.23.1 mapped to 000b462d5869 for company !

      INPUT

      Internet 10.10.10.1 - 000b.462d.2846 ARPA FastEthernet0

      Internet 10.10.10.2 1 0013.2004.acde ARPA FastEthernet0

      Internet 10.10.10.3 7 0800.4ec8.94ac ARPA FastEthernet0

      Thanks again for everyone's comments, I'm looking forward to more, I'm hooked!

        Also, Here is the parts of the oui.txt file that should match, sorry for not putting this up earlier.

        I should also state, for completeness, that im using Strawberry perl 5.12.0.1 for Windows on an XP platform and have no ability to get cpan modules from work due to the firewall/proxy rules. :(

        00-13-20 (hex) Intel Corporate 001320 (base 16) Intel Corporate Lot 8, Jalan Hi-tech 2/3 Kulim Hi-Tech Park Kulim Kedah 09000 MALAYSIA 00-0B-46 (hex) Cisco 000B46 (base 16) Cisco 80 West Tasman Dr. SJ-M/1 San Jose CA 95134 UNITED STATES 08-00-4E (hex) 3COM EUROPE LTD. 08004E (base 16) 3COM EUROPE LTD. 3COM CENTRE BOUNDARY WAY, HEMEL HEMPSTEAD HERTFORSHI UNITED KINGDOM UNITED
Re: Regex matching part of one hash key to another
by oko1 (Deacon) on Jan 07, 2011 at 00:03 UTC

    It would help a lot if we could see some sample input - doesn't have to be the real thing, just the real structure. Meanwhile, just for the heck of it, here's a bit of cleanup for your code. I got queasy looking at all those hard 'or's and square brackets. :)

    #!/usr/bin/perl -w use strict; my %oui; open my $list1, "oui.txt" or die "oui.txt: $!\n"; while (<$list1>){ if (/^(.*?) {5}\(base 16\)\t\t(.*)$/) { $oui{$1} = $2; } } close $list1; while (<>){ if (/((?:\d+\.){3}\d+).*([\w.]{14})/i){ (my $temp = $2) =~ tr/.//d; print "$1 mapped to $temp for company ", $oui{substr $temp, 0, + 6}, "\n"; } }
    -- 
    Education is not the filling of a pail, but the lighting of a fire.
     -- W. B. Yeats

      Sorry for the double post :s

      Here is a sample of the data im trying to search on. The IPs and MACs were changed from what the actual data to be able to continue working here. I have been at perl for approximately 1 month off and on and haven't written any programs since school 18 years ago so I know my code is quite rough around the edges. I used the Learning Perl "Llama" book from O'Reilly and most of this is taken from the examples and adapted to this program. This is something I learned to help with an inventory project and I hope to get better and find more uses for perl as I am hooked on its power, I know Ineed to learn much much more than I already do and I'm hoping I didn't bite off more than I can chew with this project. Thanks for the replies :)

      Internet 10.10.10.1 - 000b.462d.2846 ARPA FastEthernet0

      Internet 10.10.10.2 1 0013.2004.acde ARPA FastEthernet0

      Internet 10.10.10.3 7 0800.4ec8.94ac ARPA FastEthernet0

      I get the same output when running this, it matches only one of the iterations then just blanks afterwards. I'm starting to see the code within the compactness, much more effecient than what I blew up :). I'm wondering if somehow the substr is changing the key and causing the iterations to fail? Again, I'm very very new to this. Thanks!

      OUTPUT

      10.10.10.1 mapped to 000b462d2846 for company

      10.10.10.2 mapped to 00132004acde for company Intel Corporate

      10.10.10.3 mapped to 08004ec894ac for company

      INPUT

      Internet 10.10.10.1 - 000b.462d.2846 ARPA FastEthernet0

      Internet 10.10.10.2 1 0013.2004.acde ARPA FastEthernet0

      Internet 10.10.10.3 7 0800.4ec8.94ac ARPA FastEthernet0

Re: Regex matching part of one hash key to another
by roboticus (Chancellor) on Jan 06, 2011 at 23:41 UTC

    KevinNC:

    You should be able to just pull out the part of the OUI.TXT file that contain the lines used by your input data. Then we can easily test it.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      OUI.txt isn't the problem; it's available here. It's his other data, the log file (?) that he's parsing.

      -- 
      Education is not the filling of a pail, but the lighting of a fire.
       -- W. B. Yeats

        Here is a sample of the data im trying to search on. The IPs and MACs were changed from what the actual data to be able to continue working here. I have been at perl for approximately 1 month off and on and haven't written any programs since school 18 years ago so I know my code is quite rough around the edges. I used the Learning Perl "Llama" book from O'Reilly and most of this is taken from the examples and adapted to this program. This is something I learned to help with an inventory project and I hope to get better and find more uses for perl as I am hooked on its power, I know Ineed to learn much much more than I already do and I'm hoping I didn't bite off more than I can chew with this project. Thanks for the replies :)

        Internet 10.10.10.1 - 000b.462d.2846 ARPA FastEthernet0

        Internet 10.10.10.2 1 0013.2004.acde ARPA FastEthernet0

        Internet 10.10.10.3 7 0800.4ec8.94ac ARPA FastEthernet0

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://880962]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2024-04-19 03:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found