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

Hello monks, first of all im a perl begginer so im very limited in writing effective code. So what i want to do is to scan some ranges of ips, i did this with 4 nested for loops, now i dont want to scan all those ranges inmediately so i wan to limit the calls to the function but dunno how to do it, so lets say i scan 1.1.1.1 to 1.1.1.255, so once entered the loop and when it reaches to 50 calls to the sub i want to stop and then wait for some results the subroutines and the results i have already sorted them out, but cant figure how to limit the loop, i.e every 50 ip's wait for results and then continue, i have tried some approaches but they dont work. I.e ive tried to put a condition and a counter it does stop at 50 but then it will left various ip's without scan, because the counter dont reach the condition . Now last thing ive tried is this code which actually works nicely, but i wanted to know if theres a cleaner and effective way to do this, if possible not using any additional modules at all?
## will count the number of ipadresses that will be scanned my $rjob; { my $hjobs = 0; my($i,$j,$k,$l); for ($l=1;$l<=1;$l++){ for ($i=1;$i<=1;$i++){ for ($j=1;$j<=1;$j++){ for ($k=1;$k<=255;$k++){ $hjobs++; }; }; }; }; $rjob=$hjobs; }; print "$rjob\n"; my $maxwork = $ARGV[3] || 50; { my $conter=0; my($i,$j,$k,$l); for ($l=1;$l<=1;$l++){ for ($i=1;$i<=1;$i++){ for ($j=1;$j<=1;$j++){ for ($k=1;$k<=255;$k++){ $conter++; $rjob--; print "$l.$i.$j.$k\n"; if ($rjob < $maxwork && $conter< $maxwork){ if ($rjob==0){ ### prints are for testing if the code worked, which did print "do the work $l.$i.$j.$k $conter $rjob\n"; }; }; if ($conter >= $maxwork){ #sleep 1; print "$l.$i.$j.$k $conter $rjob\n"; $conter=0; }; }; }; }; }; };

Replies are listed 'Best First'.
Re: An efficient way to do this?
by BrowserUk (Patriarch) on Feb 06, 2008 at 12:44 UTC
Re: An efficient way to do this?
by andreas1234567 (Vicar) on Feb 06, 2008 at 13:40 UTC
    This is inspired by Hack #26 in Perl Hacks. It uses Net::Netmask to do the job:
    $ perl find_machines.pl --netblock "192.168.2.0/24" host 192.168.2.2 is up. host 192.168.2.3 is up. host 192.168.2.6 is up. host 192.168.2.10 is up. host 192.168.2.19 is up.
    --
    Andreas
Re: An efficient way to do this?
by jwkrahn (Abbot) on Feb 06, 2008 at 14:20 UTC

    You could use a closure something like this:

    $ perl -le' use Socket; sub IP_iter { my ( $start, $end ) = map unpack( "N", inet_aton $_ ), @_; my $count; sub { $count = shift; $count = $count > $end - $start ? $end - $start + 1 : $count; return map inet_ntoa( inet_aton $start++ ), 1 .. $count; } } my $ip = IP_iter "1.1.1.1", "1.1.1.12"; print for $ip->( 5 ); print ""; print for $ip->( 5 ); ' 1.1.1.1 1.1.1.2 1.1.1.3 1.1.1.4 1.1.1.5 1.1.1.6 1.1.1.7 1.1.1.8 1.1.1.9 1.1.1.10

      Whether or not you use a closure, it's probably a good idea to “turn your thinking inside-out” on this one. (And a closure, if you grok that, might be a very good way to do that.)

      Instead of putting four nested loops into the driver's seat and figuring out how to push the “pause” button after you have accumulated 50 results, put a loop (1..50) into the driver's seat.

      Each time through the loop, you call a function which, given an internal state (a vector of 4 values corresponding to the nested-loops you are now using), returns a value and the updated state. (Or it retains that state within the closure.)

      So your subroutine, conceptually, looks rather like this fragment...

      &initialize_state(\@state_vector); for my $i (1..50) { my $value = &get_next_value(\@state_vector); &process_value($i, $value); &advance_state(\@state_vector); }

      Footnote:   a “closure” is a pointer to “an instance of a subroutine.” Once you do this, the closure “has a life of its own” and each instance of the closure stands-apart from all the other instances. It's wicked-cool when you need it, but it can create strange blank looks on the faces of your colleagues... who might well decide, “well, Joe wrote this, and Joe understands it, so let's let Joe fix it ... forever...” In other words, you might have created your own wicked-cool pain in your butt. :=)