in reply to Re: getting a while loop to terminate
in thread getting a while loop to terminate

To avoid duplicate checks during the run of a program, I would optimize by making $counter a state variable

The modern perl way

use feature qw/ state /; state $counter = 1;

Or the old way, with a closure

BEGIN { my $counter = 1; sub DirPP { use Errno qw/ EACCES /; # permission denied my $word = "site"; my $name ; my $made = 0; while(1){ $name = sprintf '%s%3d', $word, $counter; last if not $made = mkdir $name, 0755 ; die $! if $! == EACCES; } return $name if $made; return; } }

Replies are listed 'Best First'.
Re^3: getting a while loop to terminate
by Aldebaran (Curate) on Apr 17, 2012 at 17:13 UTC

    I'm really having a hard time putting responses where they need to be. Since my re-working of what aaron posted and what AM posted are catching in the same place, I hope that putting the responses here doesn't offend.

    I had two big problems in the original post that have now been corrected: single quotes around the zero for false and calling for a new DirPP while in the loop that downloads the images.

    Now I'm trying to integrate the slicker versions of DirPP and stumble on the same error despite which version I try:

    $ perl tg2.pl Unrecognized LWP::UserAgent options: autodie at tg2.pl line 7 Use of uninitialized value $dir in string at tg2.pl line 16. Use of uninitialized value $dir in string at tg2.pl line 16. ... Use of uninitialized value $dir in string at tg2.pl line 16. ^C $ cat tg3.pl #!/usr/bin/perl -w use strict; use WWW::Mechanize; use LWP::Simple; use feature qw/ state /; my $domain = 'http://www.yahoo.com'; my $m = WWW::Mechanize->new( qw/ autodie 1 /); $m->get( $domain); my $counter = 0; my @list = $m->images(); my $dir = &DirPP; for my $img (@list) { my $url = $img->url_abs(); $counter++; my $filename = "$dir". "/image_". "$counter"; #line 16 getstore($url,$filename) or die "Can't download '$url': $@\n"; } sub DirPP { use Errno qw/ EACCES /; # permission denied my $word = "site"; my $counter = 1; my $name ; my $made = 0; while(1){ $name = sprintf '%s%3d', $word, $counter; last if not $made = mkdir $name, 0755 ; die $! if $! == EACCES; } return $name if $made; return; } $

    From the look of the output, the subroutine is being called many times, but to my eye, I call it only once, and that is before I enter the loop that assigns a value to $dir . (scratches head) That was aaron's version, but I induce the same behavior with AM's version:

    $ perl tg2.pl Unrecognized LWP::UserAgent options: autodie at tg2.pl line 7 Use of uninitialized value $dir in string at tg2.pl line 15. Use of uninitialized value $dir in string at tg2.pl line 15. Use of uninitialized value $dir in string at tg2.pl line 15. Use of uninitialized value $dir in string at tg2.pl line 15. Use of uninitialized value $dir in string at tg2.pl line 15. Use of uninitialized value $dir in string at tg2.pl line 15. Use of uninitialized value $dir in string at tg2.pl line 15. Use of uninitialized value $dir in string at tg2.pl line 15. ^C $ cat tg2.pl #!/usr/bin/perl -w use strict; use WWW::Mechanize; use LWP::Simple; use feature ':5.10'; my $domain = 'http://www.yahoo.com'; my $m = WWW::Mechanize->new( qw/ autodie 1 /); $m->get( $domain); my @list = $m->images(); my $counter = 0; my $dir = &DirPP; for my $img (@list) { my $url = $img->url_abs(); $counter++; my $filename = "$dir". "/image_". "$counter"; getstore($url,$filename) or die "Can't download '$url': $@\n"; } sub DirPP { use Errno qw/ EACCES /; # permission denied state $counter2 = 1; my $word = "site"; my $name ; my $made = 0; while(1){ $name = sprintf '%s%3d', $word, $counter2; last if not $made = mkdir $name, 0755 ; die $! if $! == EACCES; } return $name if $made; return; } $

    So, I'm stumped and out of guesses. That means I have no excuse to stay on the computer...off to the world of work..., happy tuesday,

      The error message isn't coming from within your subroutine; it's coming from within your loop through the images, at line 15. It's telling you that the $dir variable is undefined on each trip through the loop, although you're correct that you only assigned to it once, before the loop.

      I only have time for a quick glance right now, but I suspect that your "last if not $made" logic has gotten things a little confused. To me, that says to break out of the loop if the directory was NOT made. If it was NOT made (which would be the case if your first attempt at picking a name picked one that already existed), then $made will be false, so your first return will not trigger, and your second return will return undef, which is assigned to $die. You probably want "last if $made", because you want to break out of the loop once the directory is created, right?

      Aaron B.
      My Woefully Neglected Blog, where I occasionally mention Perl.

        Thx aaron and AM, I've got versions working now that are pretty close to what you prescribed:

        $ perl tg4.pl site_1 site_2 site_3 site_4 site_5 site_6 site_7 site_8 site_9 site_10 site_11 site_12 site_13 site_14 site_14 $ cd site_14 $ ls image_1 image_2 image_3 image_4 image_5 image_6 image_7 +image_8 ... $ cd .. $ cat tg4.pl #!/usr/bin/perl -w use strict; use WWW::Mechanize; use LWP::Simple; use feature ':5.10'; # get information about images my $domain = 'http://www.yahoo.com'; my $m = WWW::Mechanize->new(); $m->get( $domain); my @list = $m->images(); # create new folder and download images to it. my $counter = 0; my $dir = &DirPP; for my $img (@list) { my $url = $img->url_abs(); $counter++; my $filename = "$dir". "/image_". "$counter"; #line 15 getstore($url,$filename) or die "Can't download '$url': $@\n"; } sub DirPP { use Errno qw/ EACCES /; # permission denied my $word = "site"; my $counter2 = 1; my $name; my $made = 0; while(1){ $name = "$word" . "_" . "$counter2"; $counter2++; print "$name \n"; last if $made = mkdir $name, 0755 ; die $! if $! == EACCES; } print "$name \n"; return $name if $made; return; }

        Again, I'm looking for tips on style or cautions for robustness. Since one can now demonstrate two ways to do this task, reasonable people could disagree on the final touches, and the discussion might help me to understand these routines better. Here's the one that uses a state variable. Do I use it correctly?

        $ perl tg5.pl site_1 site_2 site_3 site_4 site_5 site_6 site_7 site_8 site_9 site_10 site_11 site_12 site_13 site_14 site_15 site_16 site_16 $ cat tg5.pl #!/usr/bin/perl -w use strict; use WWW::Mechanize; use LWP::Simple; use feature ':5.10'; use feature qw/ state /; state $counter3 = 1; # get information about images my $domain = 'http://www.yahoo.com'; my $m = WWW::Mechanize->new(); $m->get( $domain); my @list = $m->images(); # create new folder and download images to it. my $counter = 0; my $dir = &DirPP; for my $img (@list) { my $url = $img->url_abs(); $counter++; my $filename = "$dir". "/image_". "$counter"; #line 15 getstore($url,$filename) or die "Can't download '$url': $@\n"; } sub DirPP { use Errno qw/ EACCES /; # permission denied my $word = "site"; my $name; my $made = 0; while(1){ $name = "$word" . "_" . "$counter3"; $counter3++; print "$name \n"; last if $made = mkdir $name, 0755 ; die $! if $! == EACCES; } print "$name \n"; return $name if $made; return; }