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 local
ize 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;
}
};
}