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

I'm writing a small Perl script that will take a large list of IP addresses ( > 100), break them down into smaller chunks, and format them for our intrustion detection system (Snort). Basicly it's a var builder (for those Snort afficianados). Problem is that it's not working right, and I or anybody else that I ask around the office knows what's wrong with it. My suspicion is that it's a "string vs integer" thing.

Here's the code bit that parses thru the array of IPs (@fred) and outputs them:

$c = 0; $g = 0; foreach $w (@fred) { if ($g == 0) { print "\$g = $g and \$c = $c\n"; @fred1 = ($varname,$c); $temp_var1 = join("", @fred1); print "var $temp_var1 ["; } if ($g == 20) { print "$w]\n"; print "\$c = $c and \$g = $g\n"; $c++; @fred1 = ($varname,$c); $g = 0; print "\$g = $g"; } if ($w =~ @fred[-1]) { print "$w]\n"; } else { print "$w,"; $g++; } }
$g is set to 0; it's my counter to track how many IPs I've iterated thru. The plan is at $g == 20, close the current chunk of IPs, and start a new chunk (setting $g back to 0). $c is the chunk counter; it counts how many chunks I have. Each chunk is named from a combination of a user-supplied variable name (gotten earlier in the program) and $c. Both $g and $c are set to 0 before the foreach begins. If $g is neither 0, it outputs $w (the IP address). If $w is the last element in the array, the current chunk is closed and the foreach stops.

The problem is that the first IF statement (which checks for $g == 0) is only run thru once, at the very beginning. I've outputted the values of both $g and $c after each foreach iteration, and it'll clearly say that $g = 0 after the 20th IP, then proceed to apparently fail the $g == 0 test. Since I know that 0 == 0, I'm assuming that it must be some kind of integer vs string confusion in my code.

2005-03-17 Edited by Arunbear: Changed title from 'have no idea why this isn't working', as per Monastery guidelines

Replies are listed 'Best First'.
Re: Breaking up a list of IP addresses for Snort
by jdporter (Paladin) on Mar 15, 2005 at 23:21 UTC
    Two problems jump out at me:
    1. The test for if $w is the last one in the list is written incorrectly. It should be
      if ($w eq $fred[-1])
    2. The second if block should skip the remainder of the loop. That is, the very last if/else in the loop should not occur if $g == 20.
    That said, I think you're going about this the hard way. In addition to the splice() approach recommended above, you can iterate through the list in blocks of 20, like so:
    for ( my $chunk = 0; $chunk < @fred; $chunk += 20 ) { print "var $varname $chunk [\n"; print "$fred[$chunk]"; for my $ofs ( 1 .. 19 ) { print ",$fred[$chunk+$ofs]"; } print "]\n"; }
    However, even that looks a bit messy. How about
    for ( my $chunk = 0; $chunk < @fred; $chunk += 20 ) { local $" = ','; print "var $varname $chunk [@{[ map { $fred[ $chunk+$_] || () } 0 +.. 19 ]}]\n"; }
    This deviates from your model by having the chunks labeled 0, 20, 40..., rather than 0, 1, 2... If that part is important, you could fix it by doing (e.g.)
    print "var $varname ", $chunk/20, " . . .
Re: Breaking up a list of IP addresses for Snort
by tall_man (Parson) on Mar 15, 2005 at 23:29 UTC
    You should put in a "next" after setting $g to 0.
    $g = 0; print "\$g = $g"; next;

    Otherwise, the code will go on and add a 1 to $g in the last else block.

    Also, I would recommend you change the matching statement. I doubt you really wanted regular expression matching here:

    if ($w eq $fred[-1])

    (I'll be generous and assume you used strict and that all the variables are "my" variables declared earlier in the code. If not, you should.)

      Thanks, tall_man. That next; statement nailed it. I also changed the =~ to a eq, as recommended by all who replied. Thanks again to everybody.
Re: Breaking up a list of IP addresses for Snort
by trammell (Priest) on Mar 15, 2005 at 23:19 UTC
    You probably want to use splice():
    my $count; while (1) { $count++; my @chunk = splice(@fred,0,20); # do something with @chunk }
Re: Breaking up a list of IP addresses for Snort
by moot (Chaplain) on Mar 15, 2005 at 23:18 UTC
    Are you sure the second if block (the test for $w =~ @fred[-1] is set up correctly? Looks like it'll execute regardless of the value of $g, in which case after $g is set to 0 in the if ($g == 20) block, $g is then incremented if the regexp match fails.

    Also, are you sure about that regexp test? It's likely to only succeed if @fred[-1] is a pre-compiled re, which is doubtful given the other references to it. This is most likely why $g never tests equal to zero.