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

Here's my snippet. This program reads the passwd file (or pseudo passwd file) and then reads a file in which to ignore users and compares the users in each. If it finds the user in the ignore file it skips that person and continues on. The last statement here is forcing the while loop to constantly skip the foreach loop after the very first time it hits the last statement. See below. passwd file has lines from your passwd file, and ignoreusers has a username, one per line. excuse the bad coding :)
my $meglimit=10; my $debug=1; my $daylimit='15'; my ($user, $name, $homedir, $total, $matched); open(IGUSERS, "$workdir/ignoreusers") || die "cannot open ignoreuser +s file: $!"; open(PASSWD, "passwd") || die "cannot open passwd file: $!"; while(<PASSWD>) { chomp; $matched=2; ($user, $name, $homedir)=(split /:/)[0,4,5]; print "$user-$name-$homedir\n"; foreach my $iguser (<IGUSERS>) { print "running foreach\n"; chomp ($iguser); if ($iguser eq $user) { print "MATCHED-$iguser with $user\n"; $matched=1; last; } else { print "MATCH FAILED-$iguser with $user\n"; $matched=0; } } print "stuff\n"; if ($matched==0) { chdir "$homedir" || die "cannot chdir to $homedir: $!"; my $rawtotal=`du -smc * |grep total` || die "failed: $!"; print "DEBUG: Scanned - $user\n" if $debug==1; $rawtotal =~ m/([0-9]+)/; $total = $1; if ($total > $meglimit) { print "DEBUG: $user exceeded cap: $total\n" if $debug==1; #&checkdb(); #&notify(); #&updatedb(); } } else { print "something\n"; } print "looping\n"; } close(PASSWD); close(IGUSERS); }

Replies are listed 'Best First'.
Re: Problem with 'last' or problem with me?
by btrott (Parson) on Oct 10, 2000 at 23:35 UTC
    It's not failing because of the last; it's failing because you've aleady read to eof in IGUSERS.

    Use a hash for the ignored users:

    open FH, "$workdir/ignoreusers" or die "Can't open $workdir/ignoreusers: $!"; my %ignore; while (<FH>) { chomp; $ignore{$_}++; } close FH or die "Can't close ignoreusers: $!";
    Then you can look up an ignored user like this:
    if ($ignore{$user}) { ## Ignore this user. }
    In fact you could just stick this in your while loop:
    next if $ignore{$user};
    Then you can get rid of *all* of that $matched stuff.
Re: Problem with 'last' or problem with me?
by Fastolfe (Vicar) on Oct 10, 2000 at 23:29 UTC
    As soon as you're done reading from <IGUSERS> the first time, you can't just repeat the loop later on and continue reading from it from the beginning. The last operator simply breaks out of the loop. It doesn't affect the file pointer for IGUSERS. Thus, if you use 'last' to break out 75% of the way through your file, the next time you come into your loop, you're starting your read from 75% through the file, not the beginning. Your best option is to read everything from IGUSERS once into an array (or a hash for quick lookups), and do your comparisons against this variable in your big loop.
Re (tilly) 1: Problem with 'last' or problem with me?
by tilly (Archbishop) on Oct 10, 2000 at 23:44 UTC
    Rather than assume you know where the password file is, you should loop through fetches of getpwent. On some machines the password files may be in a binary format, available through nis, or otherwise not be where you think they are. Don't add an unnecessary assumption. :-)
(Guildenstern) RE: Problem with 'last' or problem with me?
by Guildenstern (Deacon) on Oct 10, 2000 at 23:31 UTC
    The first time through the foreach, you (may) read to the end of IGUSERS, so the next time your foreach will (may) fall out immediately since it will read an undef value. Read your IGUSERS file into an array, then loop over the array.

    Guildenstern
    Negaterd character class uber alles!
Re: Problem with 'last' or problem with me?
by ChOas (Curate) on Oct 11, 2000 at 11:07 UTC
    And combining tilly, and btrott:
    my $MegLimit=10*1024; while (my ($User,$HomeDir)=(getpwent)[0,-2]) { next if $ignore{$User}; my $CurrentUsage=(split /\s+/,`du -s -k $HomeDir`)[0]; next unless $CurrentUsage; print "$User uses to much space: $CurrentUsage Kb\n" if ($CurrentUsag +e>$MegLimit); };

    Might wanna make sure the user actually HAS a homedir
    and that it's not the root dir ;))

    Sorry, I HAD to code something... I am SO bored....