Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Split file output into array of arrays

by spickles (Scribe)
on Feb 16, 2010 at 23:19 UTC ( [id://823574]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks.

I'm trying to think of the best way to parse an output file from a Cisco router that shows me the other Cisco devices it knows about. The output separates records using a string of hyphens. I can't think of a way to parse that file and pull the multiple lines of each record out into an array? I've tried for loops, while loops, next unless, etc. But I'm still struggling to figure out the best way to loop through this file line by line and put each set of lines that make up a device record into its own array. I would like to create an AoA so that I can then parse each device record, matching lines by keywords and storing them to their own hash, which I then write to a CSV file.

I have working code that can parse the file line by line performing a loop and matching lines. I thought each record was 20 lines in length, so I stepped through the output file 20 lines at a time and sent those lines to a subroutine to perform the matching. The problems is that not all records are 20 lines in length (some are 21) and it throws it off.

I wouldn't think code posting is required, since I have nothing working for the parsing of the file. But I can post parts of the code if someone requests it. What I will post is the first couple of records of the output file:

------------------------- Device ID: HS-IDF3-C3550-A.B.org Entry address(es): IP address: 10.x.x.x Platform: Cisco WS-C3550-12G, Capabilities: Router Switch IGMP Interface: GigabitEthernet3/1, Port ID (outgoing port): GigabitEthern +et0/2 Holdtime : 158 sec Version : Cisco IOS Software, C3550 Software (C3550-IPSERVICES-M), Version 12.2( +25)SEE, RELEASE SOFTWARE (fc2) Copyright (c) 1986-2006 by Cisco Systems, Inc. Compiled Thu 02-Feb-06 20:37 by antonino advertisement version: 2 Protocol Hello: OUI=0x00000C, Protocol ID=0x0112; payload len=27, val +ue=00000000FFFFFFFF010221FF0000000000000005313DD680FF0000 VTP Management Domain: '' Duplex: full Management address(es): IP address: 10.x.x.x ------------------------- Device ID: HS-IDF3-C3550-A.B.org Entry address(es): IP address: 10.x.x.x Platform: Cisco WS-C3550-12G, Capabilities: Router Switch IGMP Interface: GigabitEthernet2/1, Port ID (outgoing port): GigabitEthern +et0/1 Holdtime : 138 sec Version : Cisco IOS Software, C3550 Software (C3550-IPSERVICES-M), Version 12.2( +25)SEE, RELEASE SOFTWARE (fc2) Copyright (c) 1986-2006 by Cisco Systems, Inc. Compiled Thu 02-Feb-06 20:37 by antonino advertisement version: 2 Protocol Hello: OUI=0x00000C, Protocol ID=0x0112; payload len=27, val +ue=00000000FFFFFFFF010221FF0000000000000005313DD680FF0000 VTP Management Domain: '' Duplex: full Management address(es): IP address: 10.x.x.x -------------------------

So you can see that records are bounded by the hyphens. If I can find a way to pull each set of multiple lines out into its own array, I'll be all set. So basically use the hyphens to indicate that a new record has begun, and until you reach the next set of hyphens, put all the lines in between into a separate array.

Regards,
Scott

Replies are listed 'Best First'.
Re: Split file output into array of arrays
by GrandFather (Saint) on Feb 16, 2010 at 23:31 UTC

    Instead of reading a 'line' at a time read a 'record' at a time. Set $/ to the record separator ("-------------------------\n" in this case) and away you go:

    use strict; use warnings; use Data::Dump; local $/ = "-------------------------\n"; my @records; while (<DATA>) { chomp; next unless length; push @records, [split "\n"]; } print Data::Dump::dump (\@records); __DATA__

    Given the data supplied by the OP prints:

    [ [ "Device ID: HS-IDF3-C3550-A.B.org", "Entry address(es):", " IP address: 10.x.x.x", "Platform: Cisco WS-C3550-12G, Capabilities: Router Switch IGMP", "Interface: GigabitEthernet3/1, Port ID (outgoing port): GigabitE +thernet0/2", "Holdtime : 158 sec", "", "Version :", "Cisco IOS Software, C3550 Software (C3550-IPSERVICES-M), Version +12.2(25)SEE, RELEASE SOFTWARE (fc2)", "Copyright (c) 1986-2006 by Cisco Systems, Inc.", "Compiled Thu 02-Feb-06 20:37 by antonino", "", "advertisement version: 2", "Protocol Hello: OUI=0x00000C, Protocol ID=0x0112; payload len=27 +, value=00000000FFFFFFFF010221FF0000000000000005313DD680FF0000", "VTP Management Domain: ''", "Duplex: full", "Management address(es):", " IP address: 10.x.x.x", ], [ "Device ID: HS-IDF3-C3550-A.B.org", "Entry address(es):", " IP address: 10.x.x.x", "Platform: Cisco WS-C3550-12G, Capabilities: Router Switch IGMP", "Interface: GigabitEthernet2/1, Port ID (outgoing port): GigabitE +thernet0/1", "Holdtime : 138 sec", "", "Version :", "Cisco IOS Software, C3550 Software (C3550-IPSERVICES-M), Version +12.2(25)SEE, RELEASE SOFTWARE (fc2)", "Copyright (c) 1986-2006 by Cisco Systems, Inc.", "Compiled Thu 02-Feb-06 20:37 by antonino", "", "advertisement version: 2", "Protocol Hello: OUI=0x00000C, Protocol ID=0x0112; payload len=27 +, value=00000000FFFFFFFF010221FF0000000000000005313DD680FF0000", "VTP Management Domain: ''", "Duplex: full", "Management address(es):", " IP address: 10.x.x.x", ], ]

    True laziness is hard work

      Thank you!! So to access each array, it would be

      $records[0][0]<br/> $records[0][1]<br/> $records[0][2]<br/> $records[1][0]<br/> $records[1][1]<br/> $records[1][2]<br/> . . .

      The reason I ask is that each array created and pushed to @records is not explicitly named.

      Regards,
      Scott

        You asked for an array of arrays. If you wanted an array of hashes or something else you should have said so. Maybe your sub that performs the matching can sort it out? Of course I can't see that code so it's not clear where or what your current problem is.


        True laziness is hard work
Re: Split file output into array of arrays
by colwellj (Monk) on Feb 16, 2010 at 23:38 UTC
    Scott,

    Try something akin to this;
    N.B code is untested and I've probably screwed up the syntax somewhere.
    my $arraycount=0; my @array; while(<INPUT>){ #New record so new top level item if($_ =~ /^-/){ $arraycount++; }else{ #force array scalar to be a lower level array. push @{$array[$arraycount]}, $_; } }
    or you could do both your steps at once.
    my $arraycount=0; my @array; while(<INPUT>){ #New record so new top level item if($_ =~ /^-/){ $arraycount++; }else{ #force array scalar to be a lower level HASH. my ($hkey,$hdet) = split/:/,$_; ${$array[$arraycount]}{$hkey} = $hdet; } }

      Keeping a count of elements in an array in Perl has rather a bad smell. Instead you could:

      my @records; while (<DATA>) { if ($_ =~ /^-/) { # New record push @records, []; next; } next if !@records; push @{$records[-1]}, $_; }

      True laziness is hard work

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (3)
As of 2024-04-25 20:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found