I am trying to get the names of all first level directories under given path.
I tried to use File::Find but had problems.
Can someone help me with that?
I am trying to get the names of all first level directories under given path.
I tried to use File::Find but had problems.
Can someone help me with that?
I'm running ActivePerl 5.10.1 under Windows XP. If I wanted to get all the names of the directories under the root drive F. I would use the following code:
#!perl
opendir (DIR,'F:/');
my @folder = readdir(DIR);
foreach my $f (@folder)
{
next if ($f =~ /\./);
print "$f\n";
}
Well, this usually works because my folder names do not contain the dot. Otherwise it fails.
Okay, it seems that even my method works for my case, people would still downvote because it is faulty. So I'd have to use the official approach, the -d flag to check if a file is a directory:
The upgraded code:
#!perl
use strict;
use warnings;
opendir (DIR, "F:/");
my @files = readdir(DIR);
my @dirs = grep { -d } @files;
print @dirs;
you can use find2perl to translate your find command to perl. See perldoc find2perl for more info.
Workaround of maxdepth: (reference from Randall)
$ find2perl /home/path -type d -eval 'my $slashes = $File::Find::name =~ tr#/##;return $File::Find::prune = 1 if $slashes > 2;return if $slashes ==2'
Code:
use strict;
use File::Find ();
use vars qw/*name *dir *prune/;
*name = *File::Find::name;
*dir = *File::Find::dir;
*prune = *File::Find::prune;
sub wanted;
File::Find::find({wanted => \&wanted}, '/');
exit;
sub wanted {
eval { my $slashes = $File::Find::name =~ tr#/##;return $File::Find::prune = 1 if $slashes > 1;return if $slashes ==1 };
if ( $? == "0" && -d _ ){
print "$name --- \n";
}
}
output
$ pwd
/temp
$ tree
.
|-- dir1
| |-- subdir1
| | |-- subsubdir1
| | `-- testsubdir1.txt
| `-- testdir1.txt
|-- dir2
| |-- subdir2
| | |-- subsubdir2
| | `-- testsubdir2.txt
| `-- testdir2.txt
|-- dir3
| `-- subdir3
| `-- subsubdir3
`-- test
9 directories, 5 files
$ perl perl.pl
/temp ---
/temp/dir3 ---
/temp/dir1 ---
/temp/dir2 ---
Use the-d
file check operator:
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
my $path = $ARGV[0];
die "Please specify which directory to search"
unless -d $path;
opendir( my $DIR, $path );
while ( my $entry = readdir $DIR ) {
next unless -d $path . '/' . $entry;
next if $entry eq '.' or $entry eq '..';
print "Found directory $entry\n";
}
closedir $DIR;
use File::Spec::Functions qw( catfile );
my ($path) = @ARGV;
opendir my $DIR, $path
or die "Cannot open directory: '$path': $!";
while ( my $entry = readdir $DIR ) {
next if $entry =~ /\A\.\.?\z/;
next unless -d catfile $path, $entry;
print $entry, "\n";
}
closedir $DIR;
This worked for me.
If you don't need to traverse the entire directory hierarchy, File::Slurp is much easier to use than File::Find.
use strict;
use warnings;
use File::Slurp qw( read_dir );
use File::Spec::Functions qw( catfile );
my $path = shift @ARGV;
my @sub_dirs = grep { -d } map { catfile $path, $_ } read_dir $path;
print $_, "\n" for @sub_dirs;
And if you ever do need to traverse a hierarchy, check CPAN for friendlier alternatives to File::Find
.
File::Finder and File::Find::Rule are front-ends for File::Find
.
File::Find::Closures is worth studying to learn how to use File::Find
and how
to write closures.
File::Next uses an iterator approach to directory traversal and looks promising, although I have never used it.
Finally, in the spirit of TIMTOWTDI, here's something quick and sleazy:
my @sub_dirs = grep {-d} glob("$ARGV[0]/*");
You could use File::Find for that. For example:
use File::Find ();
File::Find::find(\&wanted, '.');
sub wanted {
if (-d) {
print "$File::Find::name\n";
}
}
For each file found under '.'
, this will call the wanted
subroutine. Inside the subroutine you can use -d
to check for a directory.
File::Find:find
descends to all subdirectories in the tree below the directory specified.
Using File::Find::Rule
#!/usr/bin/perl --
use strict;
use warnings;
use Shell::Command qw( rm_rf touch mkpath );
use autodie;
use File::Find::Rule;
Main(@ARGV);
exit(0);
sub Main{
use autodie;
my $dir = "tmp";
mkdir $dir;
#~ chdir $dir;
mkpath "$dir/a/b/c/d";
mkpath "$dir/as/b/c/d";
mkpath "$dir/ar/b/c/d";
print `tree`;
print "---\n";
print "$_\n"
for File::Find::Rule->new->maxdepth(1)->directory->in($dir);
print "---\n";
print "$_\n"
for grep -d, glob "$dir/*"; ## use forward slashes, See File::Glob
#~ chdir "..";
rm_rf $dir;
}
__END__
.
|-- test.pl
`-- tmp
|-- a
| `-- b
| `-- c
| `-- d
|-- ar
| `-- b
| `-- c
| `-- d
`-- as
`-- b
`-- c
`-- d
13 directories, 1 file
---
tmp
tmp/a
tmp/ar
tmp/as
---
tmp/a
tmp/ar
tmp/as
Or using File::Find::Rule frontend findrule
$ findrule tmp -maxdepth ( 1 ) -directory
tmp
tmp/a
tmp/ar
tmp/as