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

Hi hopefully someone can help here. i am no expert in perl but have dabbled for a while. I wrote a script to sequentially go through a list of PC names, map to the c: drive then search for .pst files then report back their names and sizes as we are planning on doing a purge to stop users using .pst files. Now i wrote the following script and it worked a treat. However i had active perl 5.2.1 installed on PC. When i distributed the script to people in other offices they all have 5.6.1 and this is the company standard at the moment. My script does not work with 5.6.1 sadly. I dont know why or what to change. Were there changes to Find::File or 'find' in 5.6.1? Do i need to call or invoke differently? Please see below code snippets:
. . . if ($MapResult == 1){ find (\&pstFind, $dir); }elsif ($MapResult == 0){ push @missedEntry,$PCName; }#end if . . . sub pstFind{ print "\n** Test Line **\n"; if (/\.PST$/ || /\.pst$/){ my $entry = "$PCName"." $File::Find::dir"."/$_\n"; my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $theres +t) = stat($_) or die "Unable to stat $_\n"; chomp $entry; $entry = "$entry" . " = $size bytes\n"; $ByteCount += $size; print "$entry\n"; open (OUTFILE, ">> $outfile"); print OUTFILE $entry; close OUTFILE; }# end if }#end sub . . .
So from this whenever the result is 1 (succesfully mapped to target c: drive) then perform the find subroutine. If a .pst file is found stick it in a log file with its location and size. There are other parts but this is the main thing. Now this is sweet with 5.2.1 but with 5.6.1 It succesfully searches against the first PC but any subsequent PCs it only searches against the first 5 files in the target directory, then ends, and goes to the next PC and so on. I also had another issue that with 5.6.1 it does not populate the @ARGV array at all. Most annoying but can workaround that. Any ideas on that one. Maybe we have a duff install of 5.6.1 on our distribution server (not allowed to dload anything either).

Replies are listed 'Best First'.
Re: Problem with Find (classic)
by tye (Sage) on Nov 17, 2006 at 18:29 UTC

    You might try adding:

    $File::Find::dont_use_nlink= 1;

    near the top. This bug in File::Find existed for many years even after I complained about it. The most recent File::Find claims that it never causes a problem, but all of the previous versions also claimed that when it clearly wasn't true. (:

    Your problem description doesn't match what I'd expect if this were the problem, however. Your problem description sounds like a bug in File::Find (like it is not properly clearing out some remembered state from the first run). But that is just a guess as well.

    If I had this problem and cared about getting File::Find fixed, then I'd use "perl -d" to see why the second run is stopping early.

    Even more likely, I'd just replace File::Find with about a dozen lines of fairly simple code, for example, Re^2: aborting File::Find::find (gotchas). :)

    - tye        

      Thanks for the advice folks, i will make the small changes you suggested. As for the main problem, it is indeed Find::File in 5.6.1 that is causing my issue. I replaced find.pm with another version and it worked ok, still like you say i am wary of File::Find now. The @ARGV thing stopped being a problem as long as i used 'perl' when executing. i.e. "perl.exe pstfind.pl arg.txt". If i just wrote "pstfind.pl arg.txt" it failed. Wonder if its because with 5.6.1 install directtory it does not like a space in the path to the bin folder. "#!c:\program files\perl\bin -w". I will have a longer look at the code you provided and see about using it instead. Thanks.
Re: Problem with Find
by GrandFather (Saint) on Nov 17, 2006 at 17:59 UTC

    Are you sure the issue is not something magical about the PCs after the first one? There are a couple of interesting coding techniques, but nothing that would cause the symptoms described and nothing that ought be affected by different minor versions of Perl.

    The @ARGV issue also sounds much more likely to be the way your script is being run than a Perl issue. Try writing a trivial script that just echos @ARGV and run that in the same context as your troublesome script. Something like:

    print "@ARGV";

    As for the coding foibles: rather than /\.PST$/ || /\.pst$/ you could consider /\.PST$/i which performs a case insensitive match.

    There is no need to concatenate sections of strings together. Just use a single string:

    my $entry = "$PCName $File::Find::dir/$_\n";

    To concatenate a string on to the end of a variable you can:

    $entry .= " = $size bytes\n";

    DWIM is Perl's answer to Gödel
Re: Problem with Find
by MonkE (Hermit) on Nov 17, 2006 at 17:35 UTC
    Would it be too much trouble to ask why you want to prevent users from archiving their important email?
      :) Users are meant to store their PST's on their home drives not local harddrives. Many reasons from security to management when they move depts and we are in the process of hardening our PCs so users will not be able to write to folders that they most likely have saved their PST in. This is really a pre-emptive find out how much is out there to see if our file servers will be able to handle the load. Its not being used to wipe their data out of meanness ;)
Re: Problem with Find
by MonkE (Hermit) on Nov 17, 2006 at 18:00 UTC
    Updated:

    According to the relevant documentation on CPAN, you need to pass the starting directory as an array. So your invocation of find() should look like this:

    find (\&pstFind, ($dir) );
    If you want more robust matching for a PST file, you could use the following regex statement instead of what you have:
    if ( /\.PST$/i ){

      Actually in that context ($dir) is no different than $dir. In fact you can write find (\&wanted, $dir1, $dir2, $dir3). Remember that Perl flattens lists when passed to a sub.

      If that were the problem find would fail completely rather than finding the first few files in some directories. If find required an array (reference) rather than a list of directories then the syntax would be:

      find (\&wanted, [$dir]);

      but find complains about that with "Can't stat ARRAY(0x1e7ac3c): No such file or directory at ...".


      DWIM is Perl's answer to Gödel