CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Finding and deleting files in a subdirectory

 



AlphaScorpious
Novice

Nov 13, 2013, 9:34 AM

Post #1 of 6 (1003 views)
Finding and deleting files in a subdirectory Can't Post

(I'm actually writing this script using MS syntax for testing purposes)

What I have is a client whose daily files we archive. There have been some staffing changes over the last year or so and it turns out that there has been no "clean up" of this directory for a couple of years. I'm learning Perl and have been asked if I can write a script to update the directory, a script that can be run whenever and will always keep the directory up to date.

It turns out that we're only supposed to keep files for 30 days. So I should have a subdirectory for the current month and the previous month, each with their respective files. They are named in the following format: MmmYY.

So far I've written the script to be able to loop through the directory, remove any subdirectory that isn't the current or previous month, and create a subdirectory for the current and/or previous month if they don't exist.

Where I'm stuck at is not being able to find/list/delete any files in a directory before deleting it. I tried rmtree with use File::Path with disasterous results - I bricked my machine because OS files started getting deleted. I'm not having a lot of luck with File::Find either. Here's the loop:


Code
$homedir = ("c:\\perlfiles\\maptest"); 
opendir (DIR, $homedir) || die "Error opening directory $homedir", $nlcr;
while(($subdir = readdir(DIR))) {
if (-d $subdir) {
if (($subdir !~ /$newdir/) && ($subdir !~ /$prevdir/)) {
rmdir $subdir;
@match = (0, 0);
} else {
if ($subdir =~ /$newdir/) {
$match[0] = 1;
} else {
$match[1] = 1;
}
}

}
}
closedir(DIR);

if ($match[0] == 0) {mkdir $newdir;}
if ($match[1] == 0) {mkdir $prevdir;}



Here's what I think is happening: Inside the maptest directory are a bunch of subdirectories in MmmYY format. The script reads each directory name and if the name ($subdir) isn't the current or previous month, it deletes it. If the name matches either the current or previous month, they are flagged as already existing. After the loop finishes, new directories are created if they are needed.

The problem comes from $subdir. I'm assuming that in each iteration of the loop it's the name of the next directory. But trying to list any files inside $subdir hasn't worked. For example, if I tried system("ls $subdir -l"); it would list everything but it lists too much - including files outside of the maptest directory.

What am I doing wrong?


Laurent_R
Veteran / Moderator

Nov 13, 2013, 10:53 AM

Post #2 of 6 (998 views)
Re: [AlphaScorpious] Finding and deleting files in a subdirectory [In reply to] Can't Post

$newdir and $prevdir are never initialized. So, the condition:

Code
if (($subdir !~ /$newdir/) && ($subdir !~ /$prevdir/)) {

is most probably not doing what you expect.

Using the pragmas:

Code
use strict; 
use warnings;

near the top of your script will force you to declare your variables, but the happy outcome is that the compiler will tell you about many of these mistakes.


AlphaScorpious
Novice

Nov 13, 2013, 11:24 AM

Post #3 of 6 (994 views)
Re: [Laurent_R] Finding and deleting files in a subdirectory [In reply to] Can't Post

Thanks for the reply. Actually, they are initialized - I just didn't post all the code, only the area that's causing the problem.

For example, if, inside the the maptest directory, I had subdirectories Jan11 thru Dec11, Jan12 thru Dec12 and Jan13 thru May13, if I run the script, it will delete all those directories and create two new ones: Nov13 and Oct13. If Apr11 and Sep12 have files, they will not get deleted and I will have Apr11, Sep12, Oct13 and Nov13.

What I need to do before deleting the directory is be able to determine if it contains files and delete them before deleting the directory.

Here's the whole script:


Code
#!/usr/bin/perl 
use warnings;
use strict;
use Time::localtime;
use File::stat;
use File::Path;
use File::Find;

#** Begin variable declaration

my $nlcr = chr(10).chr(13);
my @MMYY;
my @months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
my $homedir;
my $subdir;
my $newdir;
my $prevdir;
my @arcfiles;
my $ctr = 0;
my @match = (0, 0);

#** End variable declaration


#--- Get the current & previous months and year
#--- Change the month from a number to a 3-letter abbreviation
#--- Get the last two digits from the year and append them to the month

$MMYY[0] = localtime->mon();
$MMYY[1] = localtime->mon() - 1;
$MMYY[2] = localtime->year() + 1900;
$MMYY[2] = substr $MMYY[2], 2;

$newdir = $months[$MMYY[0]].$MMYY[2];

#--- Compensate for the current month being Jan and the previous month being Dec

if ($MMYY[1] == -1) {
$prevdir = $months[$MMYY[1]].($MMYY[2] - 1);
} else {
$prevdir = $months[$MMYY[1]].$MMYY[2];
}


#--- See if a directory for the current & previous months exists. If not, create them

chdir "\\perlfiles\\maptest";

$homedir = ("c:\\perlfiles\\maptest");
opendir (DIR, $homedir) || die "Error opening directory $homedir", $nlcr;
while(($subdir = readdir(DIR))) {
if (-d $subdir) {
if (($subdir !~ /$newdir/) && ($subdir !~ /$prevdir/)) {
rmdir $subdir;
@match = (0, 0);
} else {
if ($subdir =~ /$newdir/) {
$match[0] = 1;
} else {
$match[1] = 1;
}
}

}
}
closedir(DIR);

if ($match[0] == 0) {mkdir $newdir;}
if ($match[1] == 0) {mkdir $prevdir;}



(The $nlcr variable is my version of \n - it keep things aligned in instances where \n does not).


Laurent_R
Veteran / Moderator

Nov 13, 2013, 3:06 PM

Post #4 of 6 (988 views)
Re: [AlphaScorpious] Finding and deleting files in a subdirectory [In reply to] Can't Post

Just a possible hint. This is taken from a tutorial I wrote in French, I translated the variables, I hope I did not forget part of it.


Code
sub gothrough_dir { 
my ($path) = @_;
my @dir_entries = glob("$path/*");
foreach my $entry (@dir_entries) {
delete_file($entry) if -f $entry;
gothrough($entry) if -d $entry;
}
}


You only need to define the delete_file subroutine in accordance with your operating system...

And you start it with this command:

Code
gothrough_dir("start_dir");


I did not test anything above, and may have made mistakes, but the basic idea should work.


AlphaScorpious
Novice

Nov 14, 2013, 9:44 AM

Post #5 of 6 (975 views)
Re: [AlphaScorpious] Finding and deleting files in a subdirectory [In reply to] Can't Post

I still can't figure this out so I'll see if I can't give a better visulaization.

On my C drive is a directory called perlfiles which holds the maptest.pl file. In that directory is a subdirectory called maptest. In the maptest directory are 3 subdirectories:

perlfiles
-- maptest
---- Apr11
---- Nct13
---- Oov13

What I need to do is determine if there are any files in Apr11 and if so delete them and then delete Apr11. I tried adding this code to get a list of the files in Apr11:


Code
@_ = <$subdir\\*>; 
foreach $_ (@_) {
print $_, $nlcr;
}



so the while loop now looks like this:


Code
while(($subdir = readdir(DIR))) { 
if (-d $subdir) {
if (($subdir !~ /$newdir/) && ($subdir !~ /$prevdir/)) {
@_ = <$subdir\\*>;
foreach $_ (@_) {
print $_, $nlcr;
}
rmdir $subdir;
@match = (0, 0);
} else {
if ($subdir =~ /$newdir/) {
$match[0] = 1;
} else {
$match[1] = 1;
}
}

}
}



What ends up displaying is this:

.\Apr11
.\Nov13
.\Oct13
..\maptest.pl
Apr11\RID00010406123456
Apr11\RID00020406123456
Apr11\RID00030406123456



What I want to see is this:

RID00010406123456
RID00020406123456
RID00030406123456

I'm assuming that in the while loop that $subdir is Apr11 in the first iteration. If that's the case, then shouldn't $subdir\\* be all files in $subdir?


AlphaScorpious
Novice

Nov 15, 2013, 3:31 PM

Post #6 of 6 (947 views)
Re: [AlphaScorpious] Finding and deleting files in a subdirectory [In reply to] Can't Post

I solved it to my satisfaction. Here's the whole script is case anyone finds parts of useful:


Code
#!/usr/bin/perl 
use warnings;
use strict;
use Time::localtime;
use File::stat;
use File::Copy;

#** Begin variable declaration

my $nlcr = chr(10).chr(13);
my $homedir;
my $subdir;
my $file;
my $newdir;
my $prevdir;
my $filedate;
my @match = (0, 0); #--- 0 = False, 1 = True. [0] = current month, [1] = previous month
my @MMYY;
my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);

#** End variable declaration

#--- Get the current & previous months and year
$MMYY[0] = localtime->mon();
$MMYY[1] = localtime->mon() - 1;
$MMYY[2] = localtime->year() + 1900;

#--- Get the last two digits from the year and append them to the month
$MMYY[2] = substr $MMYY[2], 2;

#--- Change the month from a number to a 3-letter abbreviation and append the year
$newdir = $months[$MMYY[0]].$MMYY[2];

#--- Compensate for Jan having a year greater than Dec
if ($MMYY[1] == -1) {
$prevdir = $months[$MMYY[1]].($MMYY[2] - 1);
} else {
$prevdir = $months[$MMYY[1]].$MMYY[2];
}

#--- Loop through the home directory and delete all subdirectories except the current and previous months
chdir ("\\perlfiles\\maptest");
$homedir = ("c:\\perlfiles\\maptest");
opendir (DIR, $homedir) || die "Error opening directory $homedir", $nlcr;
while(($subdir = readdir(DIR))) {
#--- Ignore the . and .. directories
next if ($subdir =~ m/^\./);
if (-d $subdir) {
if (($subdir !~ /$newdir/) && ($subdir !~ /$prevdir/)) {
$subdir = $homedir."\\".$subdir;
@_ = <$subdir\\*>;
unlink @_;
rmdir $subdir;
#--- If a directory has not been deleted, alert the user
if (-d $subdir) {
print $nlcr.$subdir." was not deleted - the directory is not empty.".$nlcr;
}
#--- Neither the current nor previous months exist
@match = (0, 0);
} else {
#--- The current month exists, the previous month does not
if ($subdir =~ /$newdir/) {
$match[0] = 1;
#--- The previous month exists, the current month does not
} else {
$match[1] = 1;
}
}

}
}
closedir(DIR);

#--- See if a directory for the current & previous months exists. If not, create them.
if ($match[0] == 0) {mkdir $newdir;}
if ($match[1] == 0) {mkdir $prevdir;}

#--- Loop through any RID* files in the home directory
opendir (DIR, $homedir) || die "Error opening directory $homedir", $nlcr;
while(($file = readdir(DIR))) {
if (-f $file) {
#--- Ignore files that don't begin with RID
next unless ($file =~ m/^RID/);
#--- Get the file's last modification time
$_ = ctime(stat($file)->mtime);
#--- Get the month and the last 2 digits of the year of the modification
$filedate = substr ($_, 4,3);
$filedate = $filedate.(substr ($_, -2));
#--- Move files whose last modification equal the current and/or previous month
if (($filedate eq $newdir) || ($filedate eq $prevdir)) {
if ($filedate eq $newdir) {
move($file, $newdir);
} else {
move($file, $prevdir);
}
#--- Delete any RID* file whose date is not the current or previous month
} else {
unlink $file;
}
}
}
closedir(DIR);


 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives