http://www.perlmonks.org?node_id=161924

This snippet searches a series of directories for a file. For instance, you may want to open the file 'foo.txt', but it could be in any one of a number of directories, so you want to search them one after the other until you find it.

An analogy would be the way a shell finds a program based on the value of the PATH environment variable.

asdfgroup's remarks noted.

my $target = 'foo.txt'; my $file = do { my $target = undef; foreach my $dir( qw{ /tmp /var/tmp /foo /bar } ) { my $t = "$dir/$target"; # nb: you might want to use -e here # but -f might be what you *really* want, YMMV if( -f $t ) { $target = $t; last; } } $target; }; if( $target ) { open IN, $target or die "Cannot open $target for input: $\n"; # ... } else { die "Can't find $target.\n"; }

Replies are listed 'Best First'.
Re: Find a file in a list of directories
by asdfgroup (Beadle) on Apr 25, 2002 at 15:27 UTC
    more compact version of your code. And you should use '-e' test instead of '-t'
    #!/usr/bin/perl sub FileFinder { my ($target, @dir) = @_; return (grep {-e $_} map {"$_/$target"} @dir)[0]; } open(F, FileFinder('FileFinder.pl', qw(some/ dirs/ ./)) || die "File n +ot found") or die $!;
      IMO in general grep and map shouldn't be chained together, map can do greps job without having retraverse the array.
      return (map{-e "$_/$target" ? "$_/$target" : ()} @dir)[0];
      And frankly why bother with map and grep at all? This is much more efficient.
      sub FileFinder { my $target=shift; -e "$_/$target" && return "$_/$target" foreach @_; undef }
      Oh and before the premature optimization police arrest me, remember that we are searching a filesystem (possible remote etc) here. That call to -e could take a while and if we have to do more of them than we really need to then we could end up wasting a lot of time.

      Adjust the file test to your taste ;-)

      Yves / DeMerphq
      ---
      Writing a good benchmark isnt as easy as it might look.