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

I build a lot of tools that list of computers on my network(I'm on WINNT,as are most of the PC's I'm checking). Recently I've put together some tools to check if specific files or directories are present in a computer.

I've been able to do this with varing degrees of success by escaping to the shell and issuing commands like
my @query =`dir \\\\$cpu\\C\$\\path_to_specific_directory`
for every possible directory that could contain the folder I'm looking for. Then using grep and split on @query to find files I'm looking for.

This is very messy and un-perlish

What I would like to do is: given a known root directory (i.e. "\\$cpu\C$", remote C:\ drives). recursively search for a directory called "SomeApp\" (this shouldn't be more than two or three levels deep), and report the sub-directories one level below "SomeApp\". Is this a job for File::Find, the docs for that module didn't give any examples that seemed to apply to a problem like this.

Replies are listed 'Best First'.
Re: How do I search for a specific directory on a remote PC?
by dmmiller2k (Chaplain) on Jan 04, 2002 at 23:48 UTC

    Once you've made the connection (to "\\$cpu\C$"), File::Find should work the same as if the directory were local to the machine the perl script is running on. Your wanted sub is responsible for accepting or rejecting any particular directory entry (file or dir).

    Try running a UNIX find1 with various command line options until you get it to do exactly what you want, then run find2perl with those same options.

    1 There are a number of available UNIX-ish command sets for Win/DOS. My favorite is U/WIN.

    dmm

      File::Find works fine. I use it whenever I have a need to locate files. You just have to understand how to use the wanted function. It uses '/' instead of '\\' internally, but that's only an issue at display time. The following prints out directories it finds in a tree, starting in the current directory. You can easily modify it to act on files, store the names in a data structure, etc. Scoping issues are more quickly handled in the last example because you're not changing scope.
      use File::Find; find ( ref to function, start path(s) ) e.g.: use File::Find; find (\&wanted, '.'); sub wanted { print($File::Find::dir, "/$_\n") if -d $_; } or, just as good: use File::Find; find ( sub {print($File::Find::dir, "/$_\n") if -d $_}, '.');
      See perldoc File::Find for how to use $File::Find::dir and $_ in the wanted function.
        I decided my reply was incomplete, given the exact question you had. Here's some code that does it.
        use File::Find; use strict; our $belowpath = "common files"; our %found_dirs; find( \&foobar, 'c:/program files'); sub foobar { if ( $File::Find::dir =~ /$belowpath$/i && -d $_ ) { my $found = "$File::Find::dir/$_"; $found =~ tr/\//\\/; print "$found\n"; } }
        This prints:
        c:\program files\Common Files\Network Associates c:\program files\Common Files\Adobe c:\program files\Common Files\InstallShield c:\program files\Common Files\Symantec Shared c:\program files\Common Files\Services c:\program files\Common Files\System c:\program files\Common Files\ODBC c:\program files\Common Files\Microsoft Shared
      I have cygwin,it has a find program. That's the part in the docs that confused me, the wanted sub. Thanks for the tip.
Re: How do I search for a specific directory on a remote PC?
by particle (Vicar) on Jan 05, 2002 at 00:16 UTC
    i've gotten some mileage from this code at nt shops in the past. you need to be careful to use the proper case in file/directory names, as 'Blah' and 'blah' are different in find, even though NT doesn't differentiate.

    #!/usr/bin/perl use strict; use warnings; # use -w instead for perl < 5.6.0 use File::Find; # the dir you're 'find'ing from my $dir = shift || '.'; # the file you're looking for my $file = 'blah'; # the results you want my @results; # the function you perform on each find value sub looking_for_blah { # return the full path name if the filename is blah push(@results, $File::Find::name) if(-f $_ && $_ eq $file); }; # the result you want, using File::Find::find() # (not the external 'find' program) find \&looking_for_blah, $dir; # print your results print("my results are: @results\n");

    ~Particle

      If you find case sensitivity to be a problem (and on Win*, it doesn't make sense to not do this) then you may want to change this line:

      push(@results, $File::Find::name) if(-f $_ && $_ eq $file);

      into:

      push(@results, $File::Find::name) if((-f $_) && ($_ =~ /^$file$/i));

      I prefer extra parens for readability, though they aren't vital

      Bill
        Regexes are overkill for case insensitive comparisons... how about:
        if (lc $_ eq lc $file and -f $_)
        for speed, clarity and correctness... (your regex has issues with special chars and trailing newlines...)

        -Blake