in reply to recursive directory question
In the interests of explaining what is wrong with your code I've written a point by point summary of various lines of your code. Like merlyn I like the problem, and I hope that my advice here may be of help. I must say though that merlyn's solution or any other solution that uses File::Find is guaranteed to be better than the improvements I suggest to your code.
Some of these points may be too pedantic. Please forgive them if so.
A good start, but consider using warnings. (add a " -w" after "perl" in the first line). Author and Date comments are great, but I'd recommend you add in a line that comments on the purpose of the script too.#!usr/bin/perl # Author: Ryan Scadlock # Date: 6 July 2002 use strict;
Oops. What is $base_file? Where has that been declared? Probably got lost in the cut and paste.my $path = './'; die "The file $base_file does not exist!\n" if (!-f $base_file);
# Initiate the recursion &RecurseDirs($path);
<style whinge> Stylistically subroutine names start with lowercase characters, like variables names. This is probably a hangover from C.Oh, and that & is unnecessary thanks to your use of ()s.
is supposed to be nicer to read.</style>recurseDirs($path);
That rm line won't work. What you'll need is:rm temp;
unlink "temp.txt";
I think you want $path to be an array here, as this usage will restrict you to looking only at the first path each time. Alternately, since you're implementing your loop by using recursion perhaps you can get rid of this loop altogether. Then again, looking further down, I think you want the loop, but not here. :)sub RecurseDirs { my ($path) = @_; my $file; #Variable for a file foreach $path($path){
You open your directory here but you don't use it. Perhaps you wanted to add a call to readdir too. egopendir (DIRECTORY, $path) || die "Can't read $path\n";
and then wrap a loop around that to use each file. Probably the loop from above.my @files = readdir(DIRECTORY);
I urge you to always add a '/' character in a test like that. It's always valid to have your path be something like "/some//path//to/here", but it's rarely valid to end up with something like "somepathto/here". :)if (-d "$path$file/") { #If it's a directory...
Find! Ah yes, so you do know about that. Unfortunately in this context Perl won't know about find and so this isn't really going to help you. File::Find (as used so beautifully by merlyn below) would make this problem heaps easier.$path find -type f >temp.txt;
Nevertheless, if you wanted to use the system's find you should be writing something like:
The system command uses the shell's functionality and returns the response code. I don't really recommend this method for this example though, as a further problem is caused by the fact that find will traverse sub-directories and return all the results for each subtree. This won't really help you because you want to compare the last used times for each directory, not for whole subtrees.system("find", "$path -type f -atime +180 > temp.txt");
Once again you need to use the shell to get your first line here to work. Alternately you can count the lines manually with a while loop or get your value some other way.$str = wc temp -l; $unused = int::substr($str, 0, 1); #returns the first character as an int
If you treat $str as a number it will be treated as a number. So your second line is equivalent to $unused += 0;
Like the above, but you should rethink how you're doing things if you have to do two finds.# Count files in dir $path find -type f >temp.txt; $str = wc temp -l; $count = int::substr($str, 0, 1); #returns the first #character as an int
You might have figured that the last line isn't going to work now. You'd be right. To do this you need to open result.txt and write to it.# Yes: write full dir path to file if (($unused * 2) > $count){ $path >>result.txt; }
#!/usr/bin/perl -w use strict; my $path "./"; my @oldies = recurse_dirs($path); print "These directories have more files unused than used: \n". join("\n", @oldies), "\n"; sub recurse_dirs { my ($path) = @_; # make sure we're dealing with a directory return () unless(-d "$path"); my $used_recently = 0; my $unused = 0; my @old; my $now = time(); my $max_age = 180*24*60*60; # Open the directory, read each file in. opendir(DIRECTORY, $path) or die "Cannot open directory $path\ +n"; foreach my $file (readdir(DIRECTORY)) { # we don't want . or .. next if $file eq "." or $file eq ".."; # skip if this is a symbolic link. next if -l "$path/$file"; # it's a directory. Note that by pushing the # returned list on to our list we don't accide +ntly # clobber previous values if(-d "$path/$file") { push @old, recurse_dirs("$path/$file"); next; } # it's not a directory, so find out it's last # access time. my $last_access = (stat("$path/$file"))[8]; # increment accordingly if(($now - $last_access) > $max_age) { $unused++; # not used recently } else { $used_recently++; # used recently } } close(DIRECTORY); # There are more unused files than used recently if($unused > $used_recently) { push @old, $path; } return @old; }
Of course, doing it all by hand is nowhere near as fast as getting that lovely module File::Find to do it for you, so use merlyn's solution in preference to this.
Hope it helps.
jarich
Update: Added test for symbolic link, as per Aristotle's reminder. I'm sure there are more gotchas here.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: recursive directory question
by Aristotle (Chancellor) on Jul 08, 2002 at 13:25 UTC |