Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Regular Expressions question

by CJXJ220 (Initiate)
on Oct 29, 2012 at 18:47 UTC ( #1001403=perlquestion: print w/ replies, xml ) Need Help??
CJXJ220 has asked for the wisdom of the Perl Monks concerning the following question:

Hi All,

I'm trying to cut my teeth on doing some pattern matching for a project I am working on for my job. As an exercise I have a written a script which telnets into a Cisco router and should return an inventory of all of the T1 interfaces on that device, making a note of which interfaces are voice PRIs.

To check for an interface I show the running configuration filtered by sections which contain the line controller T1. The problem I'm running into is the code is only returning the first match of the four interfaces that are on the router I am testing with.

Here is my code below:
use Net::Ping; use Net::Telnet::Cisco; use Getopt::Long; my $host = ""; my $interface = ""; my $PRIList = ""; my $T1List = ""; my $T1Count = 0; my $PRICount = 0; GetOptions("host:s" => \ $host); if (!$host) { print "usage: perl regexp_test.pl --host=(IPAddress)"; exit; } my $p = Net::Ping->new(); if ($p->ping($host)) { print "\nDevice is online, connecting...\n\n"; my $session = Net::Telnet::Cisco->new(Host => $host); $session->login('user', 'password'); $session->cmd("term len 0"); print "Retrieving T1 controller details...\n\n"; my @check = $session->cmd("sh run | s controller T1"); print "@check\n"; while (<@check>) { # match an interface number e.g. 0/0/0, 0/1/0, etc if (m^\G[0-9]/[0-9]/[0-9]^) { $interface = $_; $T1Count++; $T1List = join ($T1List,$interface,"\n"); } # check if the interface is a PRI (pri-group timeslots 1-24) if (m^\Gpri-group^) { $PRICount++; $PRIList = join ($PRIList,$interface,"\n"); } } if ($T1Count > 0) { print "T1 Controller Summary:\n\n"; print "$T1Count total T1 interfaces\n"; print $T1List; print "$PRICount total voice PRI(s)\n"; print $PRIList; } else { print "No T1 interfaces found"; } $session->close; } else { print "\nDevice OFFLINE!! Connection aborted!!\n\n"; } $p->close();
Here is the output from the script as it is now:
C:\perl scripts>perl regexp_test.pl --host 10.22.49.19 Device is online, connecting... Retrieving T1 controller details... controller T1 0/0/0 framing esf linecode b8zs cablelength long 0db pri-group timeslots 1-24 controller T1 0/0/1 framing esf linecode b8zs cablelength long 0db controller T1 0/1/0 framing esf linecode b8zs cablelength long 0db controller T1 0/1/1 framing esf linecode b8zs cablelength long 0db T1 Controller Summary: 1 total T1 interfaces 0/0/0 1 total voice PRI(s) 0/0/0
Based on the return of the output of the show command I am expecting the output to be this:
C:\perl scripts>perl regexp_test.pl --host 10.22.49.19 Device is online, connecting... Retrieving T1 controller details... controller T1 0/0/0 framing esf linecode b8zs cablelength long 0db pri-group timeslots 1-24 controller T1 0/0/1 framing esf linecode b8zs cablelength long 0db controller T1 0/1/0 framing esf linecode b8zs cablelength long 0db controller T1 0/1/1 framing esf linecode b8zs cablelength long 0db T1 Controller Summary: 4 total T1 interfaces 0/0/0 0/0/1 0/1/0 0/1/1 1 total voice PRI(s) 0/0/0
Any ideas what I am doing wrong that I'm not getting the desired output? Any help you can provide is greatly appreciated.

Comment on Regular Expressions question
Select or Download Code
Re: Regular Expressions question
by roboticus (Canon) on Oct 29, 2012 at 19:05 UTC

    CJXJ220:

    It looks like you're using join incorrectly in your data collection loop. The join function uses the first item in its argument list as a separator which is placed between all the other items in the list. It looks like you're using it as a concatenator, which it will fail miserably at (at least the way you use it).

    For example: print join('a','b') will print the letter b on your console, and print join('a','b','c') will print "bac". Normally, you'd use it like print join(", ", 'a', 'b','c') to get a nicely formatted list: "a, b, c".

    So you can change:

    $T1List = join ($T1List,$interface,"\n");

    to

    $T1List = $T1List . $interface . "\n";

    or you can build an array to hold your interfaces, and join them at the end.

    Update: Fixed example (to "bac") ... thanks for the catch johngg!

    ...roboticus

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

Re: Regular Expressions question
by NetWallah (Abbot) on Oct 29, 2012 at 19:11 UTC
    It seems like "while (<@check>)" should be:
    for (@check)
    because "@check" is not a file handle.

                 "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."           -Confucius

Re: Regular Expressions question
by CJXJ220 (Initiate) on Oct 29, 2012 at 20:20 UTC
    Thanks for the suggestions.

    I switched my join statement to use concatenation but it is giving the same output.

    Switching while(<@check>) with for(@check) does not match anything as the script now returns no interfaces. Do I now need to change how I am checking for the patterns within @check?

    Updated code and script output below:
    use Net::Ping; use Net::Telnet::Cisco; use Getopt::Long; my $host = ""; my $interface = ""; my $PRIList = ""; my $T1List = ""; my $T1Count = 0; my $PRICount = 0; GetOptions("host:s" => \ $host); if (!$host) { print "usage: perl regexp_test.pl --host=(IPAddress)"; exit; } my $p = Net::Ping->new(); if ($p->ping($host)) { print "\nDevice is online, connecting...\n\n"; my $session = Net::Telnet::Cisco->new(Host => $host); $session->login('user', 'password'); $session->cmd("term len 0"); print "Retrieving T1 controller details...\n\n"; my @check = $session->cmd("sh run | s controller T1"); print "@check\n"; for (@check) { # match an interface number e.g. 0/0/0, 0/1/0, etc if (m^\G[0-9]/[0-9]/[0-9]^) { $interface = $_; $T1Count++; $T1List = $T1List . $interface . "\n"; } # check if the interface is a PRI (pri-group timeslots 1-24) if (m^\Gpri-group^) { $PRICount++; $PRIList = $PRIList . $interface . "\n"; } } if ($T1Count > 0) { print "T1 Controller Summary:\n\n"; print "$T1Count total T1 interfaces\n"; print $T1List; print "$PRICount total voice PRI(s)\n"; print $PRIList; } else { print "No T1 interfaces found"; } $session->close; } else { print "\nDevice OFFLINE!! Connection aborted!!\n\n"; } $p->close();
    C:\perl scripts>perl regexp_test.pl --host 10.22.49.19 Device is online, connecting... Retrieving T1 controller details... controller T1 0/0/0 framing esf linecode b8zs cablelength long 0db pri-group timeslots 1-24 controller T1 0/0/1 framing esf linecode b8zs cablelength long 0db controller T1 0/1/0 framing esf linecode b8zs cablelength long 0db controller T1 0/1/1 framing esf linecode b8zs cablelength long 0db No T1 interfaces found
    Thanks again for your help
      I think the "\G" in the regex is preventing the match. I'm not clear on what it's purpose is.
      Try "\b" instead - to me that makes more sense.

                   "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."           -Confucius

      Assumption:

      • the data after __DATA__, were what you have in your array variable named @check
      • You have only T1 interface in your data

      If true, then try this:
      use warnings; use strict; my $host = ""; my $interface = ""; my $PRIList = ""; my $T1List = ""; my $T1Count = 0; my $PRICount = 0; my @check = grep { chomp $_; $_ } <DATA>; for (@check) { if (m{([0-9]/[0-9]/[0-9])$}) { $T1Count++; $interface = $1; $T1List .= $interface . "\n"; } elsif (m{pri-group}) { $PRICount++; $PRIList .= $interface . "\n"; } } if ( $T1Count > 0 ) { print "T1 Controller Summary:\n\n"; print "$T1Count total T1 interfaces\n"; print $T1List; print "$PRICount total voice PRI(s)\n"; print $PRIList; } else { print "No T1 interfaces found"; } __DATA__ controller T1 0/0/0 framing esf linecode b8zs cablelength long 0db pri-group timeslots 1-24 controller T1 0/0/1 framing esf linecode b8zs cablelength long 0db controller T1 0/1/0 framing esf linecode b8zs cablelength long 0db controller T1 0/1/1 framing esf linecode b8zs cablelength long 0db
      OUTPUT:
      T1 Controller Summary: 4 total T1 interfaces 0/0/0 0/0/1 0/1/0 0/1/1 1 total voice PRI(s) 0/0/0
      NOTE: Please, the script above apply to OP originally modified script starting from the for loop.
      Hope, this helps.

      If you tell me, I'll forget.
      If you show me, I'll remember.
      if you involve me, I'll understand.
      --- Author unknown to me
        Here is the equivalent code, done using OO:
        use warnings; use strict; my $host = ""; my (@T1_list, $current_T1); my @check = grep { chomp $_; $_ } <DATA>; for (@check) { if (m{([0-9]/[0-9]/[0-9])$}) { push @T1_list, $current_T1 = T1->new (INTERFACE=>$1) } elsif (m{pri-group}) { $current_T1->isPRI (1); } } if ( @T1_list ) { print "T1 Controller Summary:\n\n"; print scalar(@T1_list) . " total T1 interfaces\n"; $_->PrintName for @T1_list; print scalar(grep $_->isPRI(), @T1_list) ." total voice PRI(s)\n"; $_->PrintName for (grep $_->isPRI(), @T1_list); } else { print "No T1 interfaces found"; } { package T1; sub new{ my ($class, %att) = @_; return bless ( {PRI=>0, INTERFACE=>'', %att}, $class); } sub isPRI{ my ($self, $val) = @_; defined $val or return $self->{PRI}; $self->{PRI} = $val; } sub PrintName{ print $_[0]->{INTERFACE}, "\n"; } 1; } # End of T1

                     "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."           -Confucius

        my @check = grep { chomp $_; $_ } <DATA>;

        Map should be used for this not grep. Consider the following.

        use warnings; use strict; my @check = grep { chomp $_; $_ } <DATA>; print ">>@check<<" __DATA__ line1 0 line3

        The output is:

        >>line1 line3<<

        Grep looks at the value the block returns and if true it returns $_. Map is used to do something to each element and pass along the result from each.

        To me it is clearer and simpler to do this:

        my @check = <DATA>; chomp @check;
Re: Regular Expressions question
by CJXJ220 (Initiate) on Oct 30, 2012 at 19:20 UTC
    Hi All, It's working! :)

    The \G modifier was preventing the subsuequent matches. I had included it because to my understanding it would allow the next m// to start where the previous had left off, but I guess that only applies if you are also using the global match operator \g. Once that was removed I just had to make a few tweaks to get the output formatted the way I wanted.

    Here is the working code and output:
    use Net::Ping; use Net::Telnet::Cisco; use Getopt::Long; my $host = ""; my $interface = ""; my $PRIList = ""; my $T1List = ""; my $T1Count = 0; my $PRICount = 0; GetOptions("host:s" => \ $host); if (!$host) { print "usage: perl regexp_test.pl --host=(IPAddress)"; exit; } my $p = Net::Ping->new(); if ($p->ping($host)) { print "\nDevice is online, connecting...\n\n"; my $session = Net::Telnet::Cisco->new(Host => $host); $session->login('user', 'password'); $session->cmd("term len 0"); print "Retrieving T1 controller details...\n\n"; my @check = $session->cmd("sh run | s controller T1"); print "@check\n"; for(@check) { # match an interface number e.g. 0/0/0, 0/1/0, etc if (m^([0-9]/[0-9]/[0-9])^) { $interface = $1; $T1Count++; $T1List = $T1List . $interface . "\n"; } # check if the interface is a PRI (pri-group timeslots 1-24) if (m^pri-group^) { $PRICount++; $PRIList = $PRIList . $interface . "\n"; } } if ($T1Count > 0) { print "T1 Controller Summary:\n\n"; print "$T1Count total T1 interfaces\n"; print "$T1List\n"; print "$PRICount total voice PRI(s)\n"; print "$PRIList\n"; } else { print "No T1 interfaces found"; } $session->close; } else { print "\nDevice OFFLINE!! Connection aborted!!\n\n"; } $p->close();
    C:\perl scripts>perl regexp_test.pl --host 10.22.49.19 Device is online, connecting... Retrieving T1 controller details... controller T1 0/0/0 framing esf linecode b8zs cablelength long 0db pri-group timeslots 1-24 controller T1 0/0/1 framing esf linecode b8zs cablelength long 0db controller T1 0/1/0 framing esf linecode b8zs cablelength long 0db controller T1 0/1/1 framing esf linecode b8zs cablelength long 0db T1 Controller Summary: 4 total T1 interfaces 0/0/0 0/0/1 0/1/0 0/1/1 1 total voice PRI(s) 0/0/0
    Thanks everyone for your help, greatly appreciated!

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (11)
As of 2014-10-23 17:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (126 votes), past polls