Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Why is it "While Regex"ing,...Things do NOT seem to work!

by blackadder (Hermit)
on Oct 10, 2005 at 16:59 UTC ( [id://498877] : perlquestion . print w/replies, xml ) Need Help??

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

DA....Sorry for being a right pain in the back side...

I know we have been over this before, but I've decided to read the log files line at a time rather than slurping the whole thing, and then splitting it into an array in memory.

So, the following is my full code and data.
#! c:/perl/bin/perl.exe # # use strict; use warnings; # $/="*\n"; my ($Rec,$pc_name); my ($hash,$key); while (<DATA>) { $pc_name = $1, next if (/port-channel (\d+)$/); #line 14 $Rec->{$pc_name}->{$1} = $2 if (m|(fc\d+/\d+)\s+\[(\w+)\]|); #line + 15 $key = $1, next if (/interface port-channel (\d+)$/); # line 17 $hash->{$key}->{$1} = $2 if (/switchport description To (\w+) ([\d +\.]+)/); #line 18 } for my $data (keys %{$Rec}) { print "\nPort-Channel $data : \n"; for my $data2 (keys %{$Rec->{$data}}) { print "\t$data2\n"; } } for my $data (keys %{$hash}) { print "\nInterface Port-Channel $data : \n"; for my $data2 (keys %{$hash->{$data}}) { print "\t$data2\n"; } } __DATA__ port-channel 1 Administrative channel mode is on Operational channel mode is on Last membership update succeeded First operational port is fc1/5 2 ports in total, 2 ports up Ports: fc2/5 [up] fc1/5 [up] * port-channel 3 Administrative channel mode is on Operational channel mode is on Last membership update succeeded First operational port is fc1/1 1 port in total, 1 port up Ports: fc1/1 [up] * interface port-channel 1 switchport trunk allowed vsan 1000 switchport trunk allowed vsan add 1050 switchport description To CCC219 10.33.81.56 switchport mode E interface port-channel 3 switchport trunk allowed vsan 1000 switchport trunk allowed vsan add 1010 switchport trunk allowed vsan add 1050 switchport trunk allowed vsan add 1900 switchport description To CCC215 10.33.81.52 switchport mode E
My question is: why is it if I comment lines 14 and 15, then lines 17 and 18 will work, and vise versa. But if I uncomment all of the four lines, then I get this error:
Use of uninitialized value in hash element at C:\Perl\test\mds1.pl <DATA> line 21. Use of uninitialized value in hash element at C:\Perl\test\mds1.pl <DATA> line 29. Port-Channel 1 : fc2/5 fc1/5 Port-Channel 3 : fc1/1 Interface Port-Channel : CCC215 CCC219 C:\Perl\test>
Grateful for all your help my fellow Monks.

Blackadder

Replies are listed 'Best First'.
Re: Why is it "While Regex"ing,...Things do NOT seem to work!
by Roy Johnson (Monsignor) on Oct 10, 2005 at 17:06 UTC
    Your line-14 regex is going to match anything your line-17 regex would match, and the next will prevent the following line from running (until the next pass through the loop). When the matches fail, lines 15 and 18 will both execute, and $1 may not be set.

    I think you've created some tangled spaghetti code, here, with your uses of next. I suggest you use if-else blocks.


    Caution: Contents may have been coded under pressure.
Re: Why is it "While Regex"ing,...Things do NOT seem to work!
by pg (Canon) on Oct 10, 2005 at 17:16 UTC

    Your "port-channel" regexp sucked away matches for "interface port-channel", change the first regexp to "^port-channel" should resolve the regexp issue. Also why not use a more decent and easy to uderstand if-elsif structure.

    use strict; use warnings; # $/="*\n"; my ($Rec,$pc_name); my ($hash,$key); while (<DATA>) { if (/^port-channel (\d+)$/) { $pc_name = $1; } elsif (m|(fc\d+/\d+)\s+\[(\w+)\]|) { $Rec->{$pc_name}->{$1} = $2; } elsif (/interface port-channel (\d+)/) { $key = $1; } elsif (/switchport description To (\w+) ([\d\.]+)/) { $hash->{$key}->{$1} = $2; } } for my $data (keys %{$Rec}) { print "\nPort-Channel $data : \n"; for my $data2 (keys %{$Rec->{$data}}) { print "\t$data2\n"; } } for my $data (keys %{$hash}) { print "\nInterface Port-Channel $data : \n"; for my $data2 (keys %{$hash->{$data}}) { print "\t$data2\n"; } } __DATA__ port-channel 1 Administrative channel mode is on Operational channel mode is on Last membership update succeeded First operational port is fc1/5 2 ports in total, 2 ports up Ports: fc2/5 [up] fc1/5 [up] * port-channel 3 Administrative channel mode is on Operational channel mode is on Last membership update succeeded First operational port is fc1/1 1 port in total, 1 port up Ports: fc1/1 [up] * interface port-channel 1 switchport trunk allowed vsan 1000 switchport trunk allowed vsan add 1050 switchport description To CCC219 10.33.81.56 switchport mode E interface port-channel 3 switchport trunk allowed vsan 1000 switchport trunk allowed vsan add 1010 switchport trunk allowed vsan add 1050 switchport trunk allowed vsan add 1900 switchport description To CCC215 10.33.81.52 switchport mode E
Re: Why is it "While Regex"ing,...Things do NOT seem to work!
by pboin (Deacon) on Oct 10, 2005 at 17:17 UTC

    Looks like $pc_name isn't getting its assignment when you think it should be. I modified to debug like this:

    while (<DATA>) { $pc_name = $1, next if (/port-channel (\d+)$/); #line 14 if (m|(fc\d+/\d+)\s+\[(\w+)\]|) { print "dbg: \$pc_name:'$pc_name' \$1:'$1' \$2'$2'\n"; $Rec->{$pc_name}->{$1} = $2; } $key = $1, next if (/interface port-channel (\d+)$/); # line 17 $hash->{$key}->{$1} = $2 if (/switchport description To (\w+) ([\d +\.]+)/); #line 18 }

    And the 'dbg' print to STDOUT shows that $pc_name isn't populated. I think that's your undefined key. (At least that's what seems broken to me.)

    It's not my style, but I don't like that comma-next construct. It may be valid, but I'm not personally sure how it parses, so I wouldn't use it. Take Roy_Johnson's advice and restructure and I'll bet it works out just fine...

Re: Why is it "While Regex"ing,...Things do NOT seem to work!
by Skeeve (Parson) on Oct 10, 2005 at 17:19 UTC

    As Roy Johnson correctly said, your first regex matches the same lines, your third matches. This doesn't happen, if you anchor the regex with /^.../ for the start of the line.

    I would also do it like this to not match the second regex,when it's not appropriate:

    if (my $hit= /^port-channel (\d+)$/ .. /^\s*$/) { if ($hit == 1) { $pc_name = $1; next; } $Rec->{$pc_name}->{$1} = $2 if (m|(fc\d+/\d+)\s+\[(\w+)\]|); #line + 15 } elsif (my $hit= /^interface port-channel (\d+)$/ .. /^\s*$/) { if ($hit == 1){ $key = $1; next; } $hash->{$key}->{$1} = $2 if (/switchport description To (\w+) ([\d +\.]+)/); #line 18 }


    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e;`$_'`
      I feel a donation is coming up,....thanks for putting me out of my misery :-)

      Blackadder
Re: Why is it "While Regex"ing,...Things do NOT seem to work!
by castaway (Parson) on Oct 11, 2005 at 09:16 UTC
    I'll just add, since nobody seems to have mentioned (or I missed it in all the code):

    When you run a regex, and it assigns things to $1, $2 etc, its best to copy those into other variables right away, before you do any more regexes. There is no guarantee that they will contain the same content after running another regex, in fact its generally guaranteed that they won't.

    C.