Night Walker
Night Walker

Reputation: 21260

Getting names of directories under given path

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?

Upvotes: 5

Views: 28991

Answers (9)

niken
niken

Reputation: 2611

 $path="/path/to/search";

 @files = `find $path -name myfile.name -type f`;
 print "@files\n";

Upvotes: 0

yo.
yo.

Reputation: 11

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

Upvotes: 0

innaM
innaM

Reputation: 47829

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;

Upvotes: 26

FMc
FMc

Reputation: 42411

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.

Finally, in the spirit of TIMTOWTDI, here's something quick and sleazy:

my @sub_dirs = grep {-d} glob("$ARGV[0]/*");

Upvotes: 8

ghostdog74
ghostdog74

Reputation: 342363

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 ---

Upvotes: 0

Mike
Mike

Reputation: 1851

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;

Upvotes: 1

René Nyffenegger
René Nyffenegger

Reputation: 40499

Use opendir and -d.

Upvotes: 0

Night Walker
Night Walker

Reputation: 21260

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.

Upvotes: 3

Andomar
Andomar

Reputation: 238086

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.

Upvotes: -1

Related Questions