Solved

Pattern Matching

Posted on 2004-10-06
11
503 Views
Last Modified: 2008-03-17
Oh perl gods, I need thy help...

I need help with the following pattern match:

    if (@{$$int{'vlan'}} == 903) {

Inside $$int{'vlan'} is a number.  I want to be able to evaluate this number in an if statement and then print what is stored in $$int{'description'}.

I have included the entire script I am working with below for reference and the problem appears to be at the very end.




#!/usr/bin/perl
sub findint (@) {
    my @cfg = @_;
    my @interfaces = ();
    my $line = "";
    my $intinfo = {};

    foreach $line (@cfg) {
        chomp $line;
        if ($line =~ m/^(interface)\s*(\S*)(.*)$/) {
            $intinfo = {};
            push @interfaces, $intinfo;
            $intinfo->{'intname'} = $2;
        }
        if ($line =~ m/^(\s*description)\s*(.*)$/) {
            $intinfo->{'description'} = $2;
        }
        if ($line =~ m/^(\s*switchport access vlan)\s*(.*)$/) {
            $intinfo->{'vlan'} = $2;
        }
    }
    push @interfaces, $intinfo;

    shift @interfaces;
    return @interfaces;
}

die "Usage: $0 configfile\n" unless (@ARGV);

$configfile = $ARGV[0];

open(CFG_FILE, $configfile) or die "Can not open file, $!";
while (<CFG_FILE>) {
    push @org_config, $_;
}
close (CFG_FILE) or die "Can not close file correctly";


@interfaces = findint (@org_config);
foreach $int (@interfaces) {
    if (@{$$int{'vlan'}} == 903) {
        print "$$int{'description'}\n";
    }
}
0
Comment
Question by:coorsman
11 Comments
 
LVL 84

Expert Comment

by:ozo
ID: 12241642
Did you mean to say
if( $$int{'vlan'} == 903 ){
0
 
LVL 48

Expert Comment

by:Tintin
ID: 12242492
I think your whole approach to the problem is very muddling with clunky data structures.

Could you please describe in plain English as to what your script is supposed to do.  I'm sure we can write a much neater, shorter, cleaner and clearer version for you.
0
 
LVL 18

Expert Comment

by:kandura
ID: 12243062
you could also write $int->{vlan}==903, just as you do in the sub findint.

i agree with Tintin that we could probably come up with a neater script.
- You're slurping the whole config file into an array, even though you're looping over it only once. It would be more efficient to parse the file line by line
- You're passing around arrays, while references would be more efficient
- Your regular expressions are capturing unneccessary bits; you'd be better off with only capturing what you need
- I would make the search criterium a command line parameter as well

That being said, I suppose it's kind of neat to store the records as hash refs.
0
 
LVL 84

Expert Comment

by:ozo
ID: 12243650
What is the purpose of

    push @interfaces, $intinfo;

    shift @interfaces;
0
 

Author Comment

by:coorsman
ID: 12296791
Thank you for your comments.  Please note that I have very little experience with Perl, although I do have a background in C.  I appreciate any help I can get with this.

Ok, my objective is to supply a list of vlan numbers to the script, and have it return the descriptions for the interfaces which belong to those vlans.

Below is an small example of the file I am trying to parse (from a Cisco switch).  I need to be able to supply a list of vlans to the perl script, such as 910 and 911.  I then want the perl script to either return the descriptions for use in a shell script, or execute a command with the descriptions as part of the command's arguments.


interface GigabitEthernet1/2
 description TS-1-7513-PRI
 logging event link-status
 switchport
 switchport access vlan 42
 switchport mode access
 spanning-tree portfast
!
interface GigabitEthernet2/4
 description IDAR LB EXT
 logging event link-status
 switchport
 switchport access vlan 910
 switchport mode access
 no cdp enable
 spanning-tree portfast
!
interface GigabitEthernet2/5
 description IDAR LB INT
 logging event link-status
 switchport
 switchport access vlan 911
 no cdp enable
 spanning-tree portfast


After getting the descriptions, I would execute the following command where $1|$2|$3|$4 are the descriptions to be filtered on:

indexmaker --filter title=~"$1|$2|$3|$4" --bodyopt="background="../../_themes/corporat/corbkgnd.gif"
 bgcolor="#FFFFFF" text="#000000" link="#000000" vlink="#000000" alink="#000000"" --title="ts-1-6513
-pn1" ts-1-6513-pn1.cfg ts-1-6513-pn2.cfg mw-1-6513-pn1.cfg > /var/
www/html/mrtg/test.html


The perl script above was my attempt to take example perl scripts and make this work... which hasn't exactly worked. :-)  Thanks for all the help.  
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 84

Expert Comment

by:ozo
ID: 12302924
$vlans=qr/903|910|911/;
$/="!";
while( <> ){
  push @description,/^(?:\s*description)\s*(.*)$/m if/^(\s*switchport access vlan)\s*($vlans)$/m;
}
$descriptions = join"|",map{quotemeta}@description;
system qq(indexmaker --filter title=~"$descriptions" --bodyopt="background="../../_themes/corporat/corbkgnd.gif" bgcolor="#FFFFFF" text="#000000" link="#000000" vlink="#000000" alink="#000000"" --title="ts-1-6513 -pn1" ts-1-6513-pn1.cfg ts-1-6513-pn2.cfg mw-1-6513-pn1.cfg > /var/www/html/mrtg/test.html);


0
 

Author Comment

by:coorsman
ID: 12307003
Using ozo's suggestion, I put together the following:

------
#!/usr/bin/perl
die "Usage: $0 configfile\n" unless (@ARGV);
$configfile = $ARGV[0];
open(CFG_FILE, $configfile) or die "Can not open file, $!";


$vlans=qr/903|910|911/;
$/="!";
while( <CFG_FILE> ){
      push @description,/^(?:\s*description)\s*(.*)$/m if/^(\s*switchport access vlan)\s*($vlans)$/m;
    }
$descriptions = join"|",map{quotemeta}@description;
system qq(indexmaker --filter title=~"$descriptions" --bodyopt="background="../../_themes/corporat/corbkgnd.gif" bgcolor="#FFFFFF" text="#000000" link="#0000
00" vlink="#000000" alink="#000000"" --title="VLANS" ts-1-6513-pn1.cfg ts-1-6513-pn2.cfg mw-1-6513-pn1.cfg > /var/www/html/m
rtg/test.html);

print "$vlans\n";
print "$descriptions\n";

close (CFG_FILE) or die "Can not close file correctly";
------

However, when I run this I get an error about the expression supplied for "--filter title=~".  I inserted the above print statements and got the following:

------
ERROR: invalid filter expression title=~
(?-xism:903|910|911)
                                                                 <--- blank line
------

Thanks again...
0
 
LVL 84

Expert Comment

by:ozo
ID: 12317070
It looks like /^(\s*switchport access vlan)\s*(903|910|911)$/m did not match,
or /^(?:\s*description)\s*(.*)$/m did not match.
Did you use the same configfile as your example above?
Is there any whitespace at the end of " switchport access vlan 910"?
0
 

Author Comment

by:coorsman
ID: 12337848
I was able to get a little further by adding a \s* to match the VLAN:

/^(\s*switchport access vlan)\s*($vlans)\s*$/m

However, I then got as output for $vlans and $descriptions:

(?-xism:903|910|911)
IDAR\ LB\ EXT|IDAR\ LB\ INT

I need the $descriptions field to not have the \ characters in it, just spaces.

Also, when I use my full configuration file (which is much larger and should have 80+ matches) I get the following:

|DMZPRD05\\1\-MAIL\

I think the carriage returns at the ends of the lines may be causing some of the problems... but I'm not sure how to fix them.  Is there a way to use chomp before the data is stored?
0
 
LVL 84

Accepted Solution

by:
ozo earned 300 total points
ID: 12339497
To drop the \ characters, use
$descriptions = join"|",@description;

/^\s*description\s*(.*?)\s*$/
will avoid trailing whitespace including carriage returns
0
 

Author Comment

by:coorsman
ID: 12340870
Thank you very much ozo!  The script works great.

Here is the finished product for any who are interested:

#!/usr/bin/perl
#
# filter-by-vlans.pl
#
# This script will look at a switch config (Native IOS only) and return the port descriptions
# for any ports belonging to VLANs in the given VLAN list.
#
# The script then calls MRTG's indexmaker and uses the descriptions as a filter for the
# interfaces in those VLANs.
#

die "Usage: $0 \"vlan1|vlan2|vlan3\" \"Page Description\" \"htmlfile\"\n" unless (@ARGV);

# Configure variables
$configfile = "/root/mrtg/cat-config";
$vlans=qr/$ARGV[0]/;

# Open switch config file
open(CFG_FILE, $configfile) or die "Cannot open file, $!";

# Store description only if switchport access vlan is one in $vlans list
$/="!";
while( <CFG_FILE> ){
      push @description,/^(?:\s*description)\s*(.*?)\s*$/m if/^(\s*switchport access vlan)\s*($vlans)\s*$/m;
    }

# Join descriptions with a | symbol
$descriptions = join"|",@description;

# Call indexmaker and use $descriptions as the filter
system qq(indexmaker --filter title=~"$descriptions" --bodyopt="background="../../_themes/corporat/corbkgnd.gif" bgcolor="#FFFFFF" text="#000000" link="#000000" vlink="#000000" alink="#000000"" --title="$ARGV[1]" /root/mrtg/ts-1-6513-pn1.cfg /root/mrtg/ts-1-6513-pn2.cfg /root/mrtg/mw-1-6513-pn1.cfg > "$ARGV[2]");

# Output the descriptions on the command line
print "Port Descriptions: $descriptions\n";

# Close switch config file
close (CFG_FILE) or die "Cannot close file correctly";
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

I have been pestered over the years to produce and distribute regular data extracts, and often the request have explicitly requested the data be emailed as an Excel attachement; specifically Excel, as it appears: CSV files confuse (no Red or Green h…
In the distant past (last year) I hacked together a little toy that would allow a couple of Manager types to query, preview, and extract data from a number of MongoDB instances, to their tool of choice: Excel (http://dilbert.com/strips/comic/2007-08…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now