Home > Software design >  Perl: How to search a file named ".cfg" in a directory and all it's parent directorie
Perl: How to search a file named ".cfg" in a directory and all it's parent directorie

Time:10-01

How to search a file named ".cfg" in a directory and all it's parent directories I am fetching the name as below code but i would like to know if there is any better way to do it. Also i would like to know the recursive way to do the same.

sub get_p4_config_updir($ $)
{
  my ($client_root, $cfg_file) = @_;
  # Dir from where search starts - it's a client root here
  my $cur_dir = $client_root;
  printf("**** cur_dir: $cur_dir ****\n");
  my $slashes = $cur_dir =~ y/\///;
  printf("**** no of back slashes: $slashes ****\n");
  while($slashes > 2) {
     my ($parent_dir, $b) = $cur_dir =~ /(.*)\/(.*)/;
     printf("**** parent_dir: $parent_dir, b: $b ****\n");
     $slashes--;
     if (-e "$cur_dir/$cfg_file") {
        printf("**** File exists in dir: $cur_dir ****\n");
        return $cur_dir;
     }
     $cur_dir = $parent_dir;
  }
  return "";
}

my $cfg = '.cfg';
my $dir = '/user/home/wkspace/abc/def/MAIN';
my $path = get_p4_config_updir($dir, $cfg);
if ($path ne "") {
  printf("**** File exists in dir: $path ****\n");
} else {
  printf("**** File not found ****\n");
}

CodePudding user response:

An example using Path::Tiny:

#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
use Path::Tiny;

# Returns a Path::Tiny object to the directory containing the file
# being looked for, or undef if not found.
sub get_p4_config_updir {
    my ($client_root, $cfg_file) = @_;
    my $dir = path($client_root)->realpath;
    while (1) {
        # say "Looking at $dir";
        if ($dir->child($cfg_file)->exists) {
            return $dir;
        } elsif ($dir->is_rootdir) {
            return undef;
        } else {
            $dir = $dir->parent;
        }
    }
}

my $cfg = '.cfg';
my $dir = '/user/home/wkspace/abc/def/MAIN';
say get_p4_config_updir($dir, $cfg) // "File not found";

Or a version that's similar to @rajashekar's idea of walking the directory tree by using chdir to get each directory's parent. This one uses File::chdir, which lets you localize changes to the current working directory (and restores the original when the function/scope exits), as well as providing a handy array view of the current directory and its parents that can be manipulated:

use File::chdir;

...

sub get_p4_config_updir {
    my ($client_root, $cfg_file) = @_;
    local $CWD = $client_root; # Magic happens here
    while (1) {
        # say "Looking at $CWD";
        if (-e $cfg_file) {
            return $CWD;
        } elsif ($CWD eq "/") {
            return undef;
        } else {
            pop @CWD; # CDs to the next parent directory
        }
    }
}

CodePudding user response:

You can use core libraries to do this in a platform independent, readable way without having to use cwd and possibly causing action at a distance effects in the rest of your code:

#!/usr/bin/env perl

use strict;
use warnings;

use File::Spec::Functions qw(catfile rel2abs updir);

sub get_p4_config_updir
{
    my ($dir, $file) = @_;
    $dir = rel2abs($dir);

    do {
        my $path = catfile $dir => $file;
        return $dir if -e $path;

        return if $dir eq (my $new_dir = rel2abs(catfile $dir, updir));
        $dir = $new_dir;
    } while ('NOT_DONE');

    return;
}

sub main {
    my ($cfg, $dir) = @_;

    my $path = get_p4_config_updir($dir, $cfg);

    if (defined $path) {
        printf("Found '%s' in '%s'\n", $cfg, $path);
    }
    else {
        printf(
            "Did not find '%s' in '%s' or any of its parent directories\n",
            $cfg,
            $dir,
        );
    }
}

main(@ARGV);

Output:

C:\Users\u\AppData\Local\Temp> perl p.pl linux.bin .
Found 'linux.bin' in 'C:\'

CodePudding user response:

Why deal with pathnames, when you can walk the directory structure up with .. ?

  • if the file exists in the current directory return it.
  • else go up .. and the repeat the process.
use Cwd qw(cwd);

sub search_up {
  my ($dir, $file) = @_;
  chdir($dir);

  while (1) {
    if (-e $file) {
      print "$file exists in $dir\n";
      return $dir;
    } elsif ($dir eq "/") {
      return;
    } else {
      chdir("..");
      $dir = cwd;
    }
  };
}
  •  Tags:  
  • perl
  • Related