I have been tasked with cleaning up some daily backups and I want to automate this. I have decided that Perl might just do the trick except up until about a week ago I did not know much about it. I have been doing some homework but I am stuck and would like some help.

Here is the description of problem:
When backup is run from Sharepoint it creates a new folder with a sequentially increasing name. The backups are only run during the work week. I need to delete all but 4 of the folders and only if they are older than 4 days. I need a script that runs every day but ensures I have no more or less than 4 folders the backup directory after each execution.

Below you'll see what I have so far in psuedo-code:

Populate array @folders with list of directory of backup folder
Return number of entries in folder to $check
$check = (Returned value of total entries in @folders)
While ($check > 4) {
If (-M "$folders" > 4.0) {
Rmdir ($folder)
Repopulate array @folders with current list of folders
Return new number of entries in folder to $check } Else {
STOP
}
}

Any help or suggestions on how to go about doing this would be most appreciated.

opendir(DIR,'backup_folder') or die "$!";
my @folders = readdir DIR;
close(DIR);

if(scalar @folders > 4) {
   remove_some();
}
elsif (scalar @folders < 4) {
   add_some();
}
else {
   print "4 folders, do nothing";
}
	
sub remove_some {
   a sub routine to delete some folders
}

sub add_some {
   a sub routine to add some folders
}

Well, you can remove files and directories from your path with a single find command as follows: find /path/to/backup/root -mtime 4 -exec rm -f {} \; If you also want a list of files deleted in this manner than do as follows: find /path/to/backup/root -mtime 4 -exec rm -f {} \; -print It is not necessary to write any kind of real script for this simple task. This is, of course, assuming that you are using a unix/linux variant.

Edit: Well directoriews won't be deleted, but you can do as follows with a second command to get empty (and only empty) directories find /path/to/backup/root -mtime 4 -type d -exec rmdir {} \; -print

The code KevinADC put in would probably work great, and I thank you for that. However I am doing this for Sharepoint which is running on and backing up to a windows machine. I need to find some of those same commands in a syntax that works for the Win32 environment.

I appologize for not putting that in my original post.

The second step is posing a problem for me. I've had to break it down to two parts. The first part is how do I check the age of each folder within the directory. The second part is how do I delete that checked folder if it fits the parameters.

Any more advice on that end?

rmdir($dir) if (-M $dir > 4);

directories have to be empty though to delete them like this. You could write a recursive function to delete all files and sub directories first or use the File::Path module (it's a core module) to delete a directory tree. Or use an operating system command to delete the directory even if not empty.

I know the commands, I just cannot seem to figure out how to make the $dir in your commands to actually be a folder name that will be verified, deleted, then changed to a new folder for a repeat of that process.

I get the number verification only if I put the .plx file I am running the script from in the folder above the one the backups go into. Here is what I have for that:

opendir(DIR,"backup_folder") || die "Did not open folder: $!";
my @folders = readdir DIR;
sort @folders;
if (scalar @folders > 6) { # 6 because the first two entries are . and ..
      print "There are more than 4 folders.  Go ahead\n";
      init_testing;
      } else {
            print "Not enough, stop now";
            }

The issue I have is trying to come up with a way to create a sub part that will pick one folder within backup_folder, run it through a test/delete process, check the total number of folders again then pick a different folder than the first and repeat the process.

This would look something like this:

sub init_test {
    $i = 2;
    while (scalar @folders > 6) {
        if (-M $folders[$i] > 4) {
            remove_files();
            rmdir ($folders[$i]);
            my @folders = readdir DIR;
            $i = $i + 1;
            } else {
                }
        }
 
sub remove_files {
    a subroutine to remove files in each folder needing deletion
    }

The issue I am running into with this is that when the rmdir command runs it is looking for a directory with the right name in the wrong place, in the same folder that the .plx file is running. I need to find a way to get it to specify the location when rmdir runs OR I need to find a way to get the opendir to open the same directory that the .plx file is running in. Unfortunately I have had no luck getting

opendir(DIR,"C:\Perl\Scripts\Backuptest") # This is the location of my testing folder

to work like it I had hoped it would.

you can always have the perl script chdir to the folder you are interested in:

chdir('C:/Perl/Scripts/Backuptest') or die "Can't chdir to C:/Perl/Scripts/Backuptest: $!";

Note: its safer to use forward slashes in directory paths, even if you are on windows. Windows supprts forward and back slashes in directory paths.

I am not sure if that actually helps or not. It looks like just what I need but I seem to be having an issue with my $folder variable. Perhaps you can help me understand why

chdir("C:/Perl/Scripts") || die "Can't chdir to C:/Perl/Scripts: $!";
opendir(DIR,"backuptest") || die "Did not open folder: $!";
my @folders = readdir DIR;
sort @folders;
$i = 2;
if (scalar @folders > 8) { # 8 because the first two entries are . and .. and the 2 files
 print "There are more than 4 folders.  Go ahead and delete $folder[$i]\n";
 } else {
  print "Not enough, stop now\n";
  }
closedir (DIR);

does not display the first folder or file listed in the directory.

make your test simple for now:

chdir("C:/Perl/Scripts") || die "Can't chdir to C:/Perl/Scripts: $!";
opendir(DIR,"backuptest") || die "Did not open folder: $!";
my @folders = readdir DIR;
print "$_\n" for @folders;

see what that prints

First off, I want to thank you for all your help since I started this post. I wanted to drop in real fast to give you an update on the finished code. Here it is:

chdir("C:/Perl/Scripts/backuptest") || die "Can't chdir: $!"; #needed to be top most folder containing script to get proper array listing
opendir(DIR,"backup_folder") || die "Did not open folder: $!";
@folders = grep{!/^\./}( sort readdir DIR);
closedir ("DIR");
chdir("C:/Perl/Scripts/backuptest/backup_folder") || die "Can't chdir: $!";#moved into folder containing backup directories in order to manipulate proper info
while (scalar @folders > 4 && -M $folders[0] > 4.0) {
 system ("DEL /Q $folders[0]");#delete all files within matching directory
 system ("RD /Q $folders[0]");#delete directory itself.  RD is for 2K and XP.  DELTREE for NT and others
 chdir("C:/Perl/Scripts/backuptest") || die "Can't chdir: $!";#back into parent directory for array update
 opendir(DIR,"backup_folder") || die "Did not open folder: $!";
 @folders = grep{!/^\./}( sort readdir DIR);
 chdir("C:/Perl/Scripts/backuptest/backup_folder") || die "Can't chdir: $!";#back into backup directory for further manipulation if needed.
 closedir ("DIR");
 print "@folders \n";
 next;
 }

This does exactly what I wanted it to do within the win2K system on my test machine. Now I just have to change the directories to match the backup server and off I go. Again, thanks for all the help.

very good. I noticed this in your code:

closedir ("DIR");

You should remove the double-quotes as DIR is a filehandle. No sense in getting into bad habits. ;)

One last note. The commands I used to delete the specified folders worked great on my test machine because I assumed there were no subfolders within subfolders within the specified folders. I found that they did indeed. Normally this would not be a problem because of the DOS command deltree which deletes the intended folder and all things therein. However deltree was taken out of Win2k and all versions after. Now, to get the same results you would use RD /S /Q. It took a long time for me to find that right command so I thought it might help someone else later.

This question has already been answered. Start a new discussion instead.