gwhite has asked for the wisdom of the Perl Monks concerning the following question:

I have a directory structure that is basically
client1
-project1
-project2
client2
-project1
and so on, with each client having a variable number of projects.

Once a client is inactive for a period of time we move their project to archive and delete from the active fileserver, occasionally, between the time we mark a client for archival and get the DVD burned, a new project for that client will be started. The archival is based on client, but I want to create a deletion list based on client/project. So we don't delete one of these recent projects.

My delete list should look like
rm /client1/project1
rm /client1/project2
what I can't get figured out is how to easily retrieve project directory names in the series of client directories. I am trying File::Find, but can't figure out the wanted piece to give me what I want. I would appreciate a steer in the right direction.

g_White

Replies are listed 'Best First'.
Re: Get list of first level subdirectories
by socketdave (Curate) on Jul 21, 2005 at 14:14 UTC
    This code lists directories in the current directory, and child folders one level down. I'll leave it to you to make this delete your files ;) (btw, this is pretty much straight out of the black leopard book)
    #!/usr/bin/perl -w use strict; use Cwd; sub ScanDirectory{ my ($workdir) = shift; my ($depth) = shift; $depth++; my ($startdir) = &cwd; chdir($workdir) or die; opendir(DIR, ".") or die; my @names = readdir(DIR) or die; closedir(DIR); foreach my $name (@names) { next if ($name eq "."); next if ($name eq ".."); if (-d $name) { print &cwd."/".$name."\n"; &ScanDirectory($name, $depth) if $dept +h <= 1; next; } } chdir($startdir); } &ScanDirectory(".",0);
Re: Get list of first level subdirectories
by sh1tn (Priest) on Jul 21, 2005 at 14:43 UTC
    Simple first level subdirectories list:
    my $dir = shift || "client"; my @list = (); for( glob "*$dir*" ){ -d or next; for( glob "$_/*" ){ -d or next; push @list, $_; } } $" = $/; print "@list" __END__ client1/DIR_1 client1/DIR_2 client1/DIR_3 client2/DIR_1 client2/DIR_2 client2/DIR_3 client3/DIR_1 client3/DIR_2 client3/DIR_3


      You don't need the outer loop, because glob can take care of that implicitly. And you can also use grep instead of for to build the list:
      my $dir = shift || "client"; my @list = grep -d, glob "*$dir*/*"; $" = $/; print "@list"
        # 1 2 3 #123456789012345678901234567890123 print join"\n",grep-d,glob(shift)
        33 :)


        holli, /regexed monk/
Re: Get list of first level subdirectories
by radiantmatrix (Parson) on Jul 21, 2005 at 20:42 UTC

    If you really want to use File::Find...

    ## start in the dir above your client dirs use File::Find; my @del_dirs; find(\&del_dirs, '.'); sub del_dirs { return unless -d $_; return unless $File::Find::name =~ m{^\./.+?/.+}; # at least in pro +ject level return if $File::Find::name =~ m{^\./.+?/.+?/.+}; # but no lower ### check for age or whatnot here, return if you don't want deletio +n ### push @del_dirs, 'rm '.$File::Find::name; }
    However, I doubt this is what you want to do. I would suggest:
    my @del_dirs; opendir primary, '.' or die $!; foreach my $client (readdir primary) { opendir client, $client or die $!; foreach (readdir client) { ## check date, etc. use 'next' if you want to keep push @del_dirs, 'rm '.$client.'/'.$_; } closedir client; } closedir primary;

    In either case, your delete list ends up in @del_dirs;

    The glob-based solutions above would work, too, but readdir tends to be faster than glob.

    <-radiant.matrix->
    Larry Wall is Yoda: there is no try{} (ok, except in Perl6; way to ruin a joke, Larry! ;P)
    The Code that can be seen is not the true Code
    "In any sufficiently large group of people, most are idiots" - Kaa's Law