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

I want to be able to descend down a directory path and look for a certain file name along the way in each subdirectory. Suppose I am in /www/stage/sites/MyCompany/docs/systems/foo/documentation. I want to look for a config file start in at the doc root (/www/stage/sites/MyCompany/docs), then look in the systems subdirectory, then the foo subdirectory, etc. What's the best way of going about doing this?

-peter

EDIT: Roy Johnson's response looks most promising. As was pointed out by a few here, I'm not looking to traverse ALL directories (I know File::Find is used for that). The "split" thing was what I was kinda thinking about - thanks for giving me a place to start, Roy.

  • Comment on Checking subdirectories in a given path

Replies are listed 'Best First'.
Re: Checking subdirectories in a given path
by Roy Johnson (Monsignor) on Jan 21, 2004 at 21:07 UTC
    Maybe something like (untested):
    use Cwd; my $docroot = '/www/stage/sites/MyCompany/docs'; my $cfgdir = $docroot; my $dir = getcwd; $dir =~ s{^$docroot/}{}; my (@dirs) = split '/', $dir; while (not -e "$cfgdir/filename.cfg" and @dirs) { $cfgdir .= '/' . shift(@dirs); }
    ?

    The PerlMonk tr/// Advocate
Re: Checking subdirectories in a given path
by blue_cowdawg (Monsignor) on Jan 21, 2004 at 21:03 UTC

    There are many ways you can go about this. A very quick way is to use the find2perl command to create a script that you can the modify to your heart's content to do exactly what you want it to do.

    For instnace I run:

    unixprompt> mydir=/www/stage/sites/MyCompany/docs/systems/foo/document +ation unixprompt> find2perl $mydir -depth -type d -print > myscript

    Now you will have a script called "myscript" that looks like:

    #! /usr/bin/perl -w eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' if 0; #$running_under_some_shell use strict; use File::Find (); # Set the variable $File::Find::dont_use_nlink if you're using AFS, # since AFS cheats. # for the convenience of &wanted calls, including -eval statements: use vars qw/*name *dir *prune/; *name = *File::Find::name; *dir = *File::Find::dir; *prune = *File::Find::prune; sub wanted; # Traverse desired filesystems File::Find::finddepth({wanted => \&wanted}, '/www/stage/sites/MyCompan +y/docs/systems/foo/documentation'); exit; sub wanted { my ($dev,$ino,$mode,$nlink,$uid,$gid); (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -d _ && print("$name\n"); }

    Now you can take and modify where it says "print" under the sub "wanted" and make it do whatever you want.

    You could also handroll all this instead of cheating and using find2perl....


    Peter L. Berghold -- Unix Professional
    Peter at Berghold dot Net
       Dog trainer, dog agility exhibitor, brewer of fine Belgian style ales. Happiness is a warm, tired, contented dog curled up at your side and a good Belgian ale in your chalice.
use File::Find;
by Anonymous Monk on Jan 21, 2004 at 21:10 UTC
    use File::Find; $source = '/somedir'; $somefile = 'somefile.txt'; traverse(); sub traverse { my %opts = ( wanted => \&eval_files, ); finddepth(\%opts, $source); } sub eval_files { if (-f && $_ eq $somefile) { print 'Got ', $_,"\n"; } }

    For each item within a directory, File::Find will invoke the sub &eval_files. eval_files() does blissfully throw away items that aren't files and will shriek if the the file matches the given filename. $_ contains magically the name of the current item (dir / file).

Re: Checking subdirectories in a given path
by Roger (Parson) on Jan 21, 2004 at 23:24 UTC
    An (efficient) alternative.
    use strict; use warnings; use File::Spec::Functions qw/ canonpath /; my $fullpath = '/www/stage/sites/MyCompany/docs/systems/./foo/../docum +entation///'; my $sitedoc = '/www/stage/sites/MyCompany/docs/..'; my $want = 'config.cfg'; print find_file($fullpath, $sitedoc, $want) ? "found" : "not found"; sub find_file { my ($path, $root, $want) = @_; $path = canonpath($path); $root = canonpath("$root/.."); my $found; while ($path ne $root) { $found = 1, last if -f "$path/$want"; $path =~ s!\\[^\\]+$!!; } return $found; }
Re: Checking subdirectories in a given path
by Joost (Canon) on Jan 21, 2004 at 21:02 UTC
      No, it's the canonical answer to a more common question that resembles this one. This one only wants to check the components of the path of the current working directory, between a higher level and the current depth.

      The PerlMonk tr/// Advocate