2

I have a folder called Client which contains many subfolders. I want to create a Perl script to look at each of those subfolders and check for a folder there. If it is there, I want to skip it and move on, if it is not there, I want to create it and do some processing.

How do I go about looping through all of the subfolders and checking for the directory I want? I have found a lot of information on how to get all the files in a folder and/or subfolders, but nothing on checking for a directory within each subfolder.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339

4 Answers4

12

Augh! Too much complexity in the other answers. The original question doesn't appear to be asking for a recursive traversal. As far as I can see, this is a perfectly sensible solution, and vastly more readable to boot:

foreach my $dir (glob "Client/*") {
    next if ! -d $dir;              # skip if it's not a directory
    next if -d "$dir/subfolder";    # skip if subfolder already exists
    mkdir "$dir/subfolder" or die;  # create it
    do_some_processing();           # do some processing
}

Seriously folks: opendir/readdir? Really?

Nifle
  • 11,745
  • 10
  • 75
  • 100
Andy Ross
  • 11,699
  • 1
  • 34
  • 31
  • People get the module virus and they forget how to program. At least I'm not the only one who sees this. :) – brian d foy Sep 02 '09 at 22:39
  • Amen! +1 for KISS solution :) – DVK Sep 03 '09 at 13:48
  • Although, I'm tempted to downvote for not using "$!" in the error message from mkdir :) – DVK Sep 03 '09 at 13:49
  • Nicely done; You can optimize a little by replacing `glob "Client/*"` with `grep { -d $_ } "Client/*/"` (trailing `/`) to only match directories to begin with. The `grep { -d $_ }` part is needed, because `glob()` inexplicably also matches symlinks to _files_ with globs ending in `/` (observed on v5.18.2). – mklement0 Aug 21 '15 at 19:26
4

It's pretty easy once you break it into steps. Get a list of the subdirectories with glob then see which ones don't have the second-level directory. If you are using a File::Find-like module, you are probably doing too much work:

#!perl

use strict;
use warnings;

use File::Spec::Functions;

my $start  = 'Clients';
my $subdir = 'already_there';

# @queue is the list of directories you need to process
my @queue  = grep { ! -d catfile( $_, $subdir ) }   # filter for the second level
             grep { -d }                            # filter for directories
             glob catfile( $start, '*' );           # everything below $start   
brian d foy
  • 129,424
  • 31
  • 207
  • 592
2
#!/usr/bin/perl

use strict;

use Fcntl qw( :DEFAULT :flock :seek );
use File::Spec;
use IO::Handle;

my $startdir = shift @ARGV || '.';
die "$startdir is not a directory\n"
    unless -d $startdir;
my $verify_dir_name = 'MyDir';

my $dh = new IO::Handle;
opendir $dh, $startdir or
    die "Cannot open $startdir: $!\n";
while(defined(my $cont = readdir($dh))) {
    next
        if $cont eq '.' || $cont eq '..';
    my $fullpath = File::Spec->catfile($dir, $cont);
    next
        unless -d $fullpath && -r $fullpath && -w $fullpath;
    my $verify_path = File::Spec->catfile($fullpath, $verify_dir_name);
    next
        if -d $verify_path;
    mkdir($verify_path, 0755);
    # do whatever other operations you want to $verify_path
}
closedir($dh);
chaos
  • 122,029
  • 33
  • 303
  • 309
0

The short answer is use File::FInd.

The long answer is first write a subroutine that validates the existence of the folder and if the folder is not there, create it and then do the processing needed. Then invoke the find method of the File::Find module with a reference to the subroutine and the starting folder to process all the subfolders.

David Harris
  • 2,332
  • 1
  • 13
  • 25