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

Help with logic/syntax

by randompug (Initiate)
on Jul 25, 2013 at 16:27 UTC ( [id://1046381]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, mostly a perl noob here but trying! I've hacked my way through a few things but I'm really hitting a wall with this one.

I'm trying to take some data in the format such as:

# hostname 123 hostname 123 vlan create vif1 1 2 3 4 5 6 vlan add vif1 7 8 ifconfig vif1-1 some data here ifconfig vif1-2 some data here .. ifconfig vif1-9 some data here # hostname 456 hostname 456 vlan create vif5 1 2 vlan add vif5 3 4 5 vlan add vif5 6 7 8 9 ifconfig vif5-1 some data here ifconfig vif5-2 some data here .. ifconifg vif5-9 some data here

I have read this data into an array and split it on "#" by doing the following:

$/ = undef; while ( <DATA> ) { @col=split('#',$_); $/ = \n;
I'm able to iterate through the array and find the lines I want correctly with this
foreach (@col) { print "This is element : $i\n"; if (/vlan/) { print "found a vlan line\n"; } if (/ifconfig/) { print "found an ifconfig line\n";

1. The first problem I'm having is the if lines above doesn't let me match on /^hostname/ instead of /hostname/. Thus I get false positives because hostname exists in other places when I only want to match lines that have hostname at the start.

2. When I match the vlan lines, what I want to do is count the # of words on the line (unix "wc"), read any other vlan lines thats in the current element of the array, and add this to get a total. The total # of vlans will always be the number of words on each line that starts with vlan, less 3 (for each line). For the first element above, I have 8 total vlans I need to read and then compare with the number of ifconfig lines to make sure they match.

The end goal is to count the # of vlans created and/or added and compare with the ifconfig lines to make sure if one creates 9 vlans, then there are 9 match ifconfig lines.

3. Output desired:

Hostname : hostname123 # of vlans: 8 # of ifconfig lines: 8 Hostname : hostname456 # of vlans: 9 # of ifconfig lines: 9

Replies are listed 'Best First'.
Re: Help with logic/syntax
by choroba (Cardinal) on Jul 25, 2013 at 16:53 UTC
    Your example code is problematic. Shouldn't \n be doublequoted?

    I had no problems with using /^/ for the beginning of a line - maybe because I processed the records line by line.

    #!/usr/bin/perl use warnings; use strict; $/ = "#"; while (<DATA>) { next if $. == 1; # Skipt the empty "first" record; my @lines = split /\n/; my ($vlan, $ifconfig) = (0, 0); for (@lines) { if (/^hostname/) { print "$_\n"; } elsif (/^vlan/) { $vlan++ for m/\S+/g; $vlan -= 3; } elsif (/^ifconfig/) { $ifconfig++ for m/\S+/g; $ifconfig -= 3; } } print "vlan $vlan\nifconfig $ifconfig\n"; print "WRONG!!!\n" if $vlan != $ifconfig; }
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      With my code I was able output such as:

      $ ./vlan.pl This is element : 0 This is element : 1 This is element : 2 This is element : 3 found a vlan line found an ifconfig line This is element : 4 found a vlan line found an ifconfig line

      Using choroba's code I had to change 1 thing, probably because I'm horrible at communicating :) I just commented out what to match on the ifconfig line

      } elsif (/^ifconfig/) { $ifconfig++ #for m/\S+/g; }

      because here I just want to count the lines themselves until we run out of ifconfig lines, not the number of words on each line like in the vlan example, then compare that with how many vifs we counted.

      At first I was getting this:

      hostname host97 vlan 72 ifconfig 504 WRONG!!!

      But now I get this:

      hostname host97 vlan 72 ifconfig 72

      Guess I was overcomplicating it by reading it into an array and then trying to iterate an array since I already have the data preformatted (from another script) when I opened the filehandle in this one. That too can be cleaner, but this is functional and that is what matters until we learn more!

      Thank you choroba! this gives me other ideas on other little things like this I'm trying to do!

Re: Help with logic/syntax
by kcott (Archbishop) on Jul 25, 2013 at 17:41 UTC

    G'day randompug,

    Welcome to the monastery.

    Here's a way to do this that doesn't involve slurp mode or any regexes:

    $ perl -Mstrict -Mwarnings -E ' my @data = ( "# hostname 123", "hostname 123", "vlan create vif1 1 2 3 4 5 6", "vlan add vif1 7 8 ", "ifconfig vif1-1 some data here", "ifconfig vif1-2 some data here", "..", "ifconfig vif1-9 some data here", "# hostname 456", "hostname 456", "vlan create vif5 1 2", "vlan add vif5 3 4 5", "vlan add vif5 6 7 8 9", "ifconfig vif5-1 some data here", "ifconfig vif5-2 some data here", "..", "ifconifg vif5-9 some data here", ); my ($hostname, @hosts, %host_data); for (@data) { my @fields = split; if ($fields[0] eq "hostname") { push @hosts => ($hostname = $fields[1]); } elsif ($fields[0] eq "vlan") { $host_data{$hostname}{vlan} += @fields - 3; } elsif ($fields[0] eq "ifconfig") { ++$host_data{$hostname}{ifconfig}; } } for (@hosts) { say "Hostname: $_"; say "vlans: $host_data{$_}{vlan}"; say "ifconfigs: $host_data{$_}{ifconfig}"; } ' Hostname: 123 vlans: 8 ifconfigs: 3 Hostname: 456 vlans: 9 ifconfigs: 2

    I don't know where your real data is coming from: you should be able to just change "for (@data) {" to "while (<$file_handle>) {" (or whatever's appropriate) and get the same results. I'll leave you to check the vlan/ifconfig count. Your one instance of ifconifg may be intended for testing or perhaps just a typo.

    -- Ken

Re: Help with logic/syntax
by hdb (Monsignor) on Jul 25, 2013 at 18:09 UTC

    IMHO the best data structure is an array of hashes. Each time you encounter a hostname line, you push a new hash onto the array and store the hostname. For each of the following lines you can refer to that hash by $array[-1] until the next hostname line. See below:

    use strict; use warnings; my @results; while(<DATA>){ push @results, {'hostname' => $1} if /^(hostname.*)/; # push + a new hash into the array $results[-1]->{'vlan'}+= split(/\s+/) - 3 if /^vlan/; # numb +er of words - 3 $results[-1]->{'ifconfig'}++ if /^ifconfig/; # one +for each ifconfig } for( @results ) { print "Hostname : $_->{'hostname'}\n"; print "# of vlans: $_->{'vlan'}\n"; print "# of ifconfig lines: $_->{'ifconfig'}\n\n"; } __DATA__ # hostname 123 hostname 123 vlan create vif1 1 2 3 4 5 6 vlan add vif1 7 8 ifconfig vif1-1 some data here ifconfig vif1-2 some data here ifconfig vif1-9 some data here # hostname 456 hostname 456 vlan create vif5 1 2 vlan add vif5 3 4 5 vlan add vif5 6 7 8 9 ifconfig vif5-1 some data here ifconfig vif5-2 some data here ifconfig vif5-9 some data here
Re: Help with logic/syntax
by Anonymous Monk on Jul 25, 2013 at 16:45 UTC

    the split function requires a regex.

      I agree that it is usually better practice to use a regex as a split pattern (and I have upvoted this post, contrary to the majority of viewers as of this writing), because split is really geared on using regex patterns (IMHO), but saying that it requires a regex is somewhat of an exageration: it can work with other expressions like a single character or even a string. Although, with a string, the results can sometimes be sometimes somewhat unexpected when the string contains wierd characters... But using a single character such as '#', as done by the OP, does work fine:

      DB<1> $c = "jdskq#jdskl" DB<2> @d = split '#', $c; DB<3> x @d 0 'jdskq' 1 'jdskl'

        blah blah blah

        split demands a regex, it doesn't accept strings, it takes patterns, doesn't matter how you quote '#' its a regex pattern

      the split function requires a regex.
      A string is also a regex, if not a very interesting one.

      -QM
      --
      Quantum Mechanics: The dreams stuff is made of

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (5)
As of 2024-04-23 18:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found