Re: Directory recursion on win32
by Thelonius (Priest) on Aug 04, 2003 at 14:21 UTC
|
Although you may want to use File::Find as other respondents suggested, you can get your subroutine to work by declaring your variables with "my" inside your subroutine Recurse. #!wperl
use strict;
use Win32;
sub Recurse;
Recurse ($ARGV[0]);
sub Recurse
{
my ($DirItem);
my ($Formatted);
my ($PWD);
($PWD) = @_;
opendir(DIR, $PWD);
my @DirList = readdir(DIR);
closedir DIR;
foreach $DirItem (@DirList)
{
$Formatted = $DirItem . "z";
if ( -d $DirItem &&$DirItem ne "." && $DirItem ne "..")
{
&Recurse ($PWD . "\\" . $DirItem);
}
if ($DirItem ne "." && $DirItem ne "..")
{
rename("$PWD\\$DirItem","$PWD\\$Formatted");
}
}
}
Updated: Changed
rename($DirItem,$Formatted);
to
rename("$PWD\\$DirItem","$PWD\\$Formatted");
That should fix it.
| [reply] [d/l] |
|
|
Okay, moved the definitions inside the sub, and added a count, to see how many times it recursed. Extra info is that It will rename the files (and dirs) in the current directory (so the initial given path), but it won't dig deeper. So the problem is with how i pass path info to Recurse?
| [reply] |
|
|
Here is a script that I wrote which recurses down a win32 directory strcuture and writes a logfile which tells the directories and all the contents.. I think the recursion model might be useful for you. Although it doesn't use File::Find
#!/Perl/bin/perl
use IO::File;
use strict;
print "Enter the directory to map: ";
my $dir = <STDIN>;
chomp($dir);
my $log = new IO::File;
$log->open(("> c:\\log.txt")) or die "$!";
$log->write("Map of: ".$dir."\n",length("Map of: ".$dir."\n"));
$dir =~ s{\\}{\\\\}g;
mapMe($dir);
$log->close;
##Recursive routine to print out all the files & folders under a given
+ root node
sub mapMe
{
#Get the parameter
my $handle = shift;
#Open the directory passed to the subroutine
opendir(SPROUT,$handle);
#read the entries
my @entries = readdir(SPROUT);
#Close the directory
closedir(SPROUT);
my $log_entry;
#Skip the . and .. entries
foreach my $i (2..scalar(@entries))
{
#Format the handle for the next call
my $param_handle = $handle."\\".$entries[$i];
#If its a directory and its not null
if(opendir(TEST,$param_handle) and $entries[$i])
{
#Close the directory
closedir(TEST);
#Strip the handle for log writing purposes
$handle =~ s{\\\\}{\\}g;
#Construct and write the log
$log_entry = "\n".$handle."\\".$entries[$i]."\n";
$log->write($log_entry,length($log_entry));
#recurse the directory
mapMe($param_handle);
}
elsif($entries[$i])
{
#Construct and write the log
$log_entry = "*".$entries[$i]."\n";
$log->write($log_entry,length($log_entry));
}
}
}
| [reply] [d/l] |
Re: Directory recursion on win32
by derby (Abbot) on Aug 04, 2003 at 14:18 UTC
|
File::Find is your friend.
(note to self): Add "Recursive Directory Walker" to list of "must" implement
requirements for self-respecting perl developers (along with an HTML templating system
and DB abstraction layer).
-derby | [reply] |
Re: Directory recursion on win32
by broquaint (Abbot) on Aug 04, 2003 at 14:48 UTC
|
Further to what others have said you might want to check that you're able to open the directories e.g
opendir(DIR, $PWD) or return warn("$0: $! [$PWD]");
...
So you'll get a warning and the sub will return. You may also want to check rename for success.
Of course, you could always do this with File::Find::Rule, the spiritual successor to File::Find, like so
use File::Find::Rule;
rename $_ => "${_}z" or warn "$0: $! [$_]"
for find(file => in => $ARGV[0]);
See. the File::Find::Rule docs for more info.
HTH
_________ broquaint | [reply] [d/l] [select] |
|
|
Okay, had something similar but ripped out for the query, as it happened, also took it out of my version ;) so cheers!
| [reply] |
Re: Directory recursion on win32
by Abigail-II (Bishop) on Aug 04, 2003 at 14:15 UTC
|
Is there a reason you aren't using File::Find?
Abigail | [reply] |
|
|
Hi,
Really REALLY swift responses, so for now i'll assume you are boths scripts ;)
The test tree is about 4 directories deep, and contains about 50 files, some directories merely contain subdirs, and some nothing at all.
As far as a reason why I am not using File::Find the reason would be ignorance. I have constructed something similar to this script which worked fine in unix, but am having probs, in win32. I just stuck with the same method. The unix scripts can be cut and pasted if you think it would be of any help.
cheers again
ant
| [reply] |
|
|
use File::Find;
sub rename_file {
my $fullpath = $File::Find::name;
rename ($fullpath, $fullpath.'z') ||
warn "Failed to rename $fullpath\n";
}
find (\&rename_file, $path);
What could be simpler?
As others have pointed out, modules are there to help you. Not using them out of ignorance is probably not what you want to do for too long: you miss out on all the fun!
| [reply] [d/l] |
Re: Directory recursion on win32
by fourmi (Scribe) on Aug 04, 2003 at 16:27 UTC
|
SOLVED!
Special thanks to Grygonos, and thanks to everyone else who responded so quickly!! I adapted Grygonos' code, and managed to make it work, things that may have made a difference were the initial pwd chomp, and the use of \\\\ in places. for interest the working code follows, will probably adapt further but this works.
#!wperl
use IO::File;
use strict;
my $dir = $ARGV[0];
chomp($dir);
$dir =~ s{\\}{\\\\}g;
mapMe($dir);
sub mapMe
{
my $handle = shift;
opendir(SPROUT,$handle);
my @entries = readdir(SPROUT);
closedir(SPROUT);
foreach my $i (2..scalar(@entries))
{
my $param_handle = $handle."\\".$entries[$i];
if(opendir(TEST,$param_handle) and $entries[$i])
{
closedir(TEST);
$handle =~ s{\\\\}{\\}g;
my ($newdirname)= $handle."\\".$entries[$i]. "z";
rename ($handle."\\".$entries[$i], $newdirname);
mapMe($newdirname);
}
elsif($entries[$i])
{
my ($newname) = $handle."\\".$entries[$i] . "z";
rename ($handle."\\".$entries[$i], $newname);
}
}
}
cheers!!
ant | [reply] [d/l] |
Re: Directory recursion on win32
by fglock (Vicar) on Aug 04, 2003 at 15:11 UTC
|
rename(
$PWD . "\\" . $DirItem,
$PWD . "\\" . $Formatted
);
| [reply] [d/l] |
|
|
Ahh, okay that has gained me an extra level of recursion. Can i get confirmation that $PWD will take on the new pwd on each recursion not, maintain the previous value? (i'm not fully understanding the practical differences between $def, my $def, and my ($def) )
| [reply] |
|
|
sub Recurse
{
my ($PWD) = @_;
This makes $PWD exist only during this call to this block.
Recurrent calls will create new versions of $PWD.
The parenthesis make a list, and $PWD is
the first value. This list gets aliased to the
values in the @_ list, such that $PWD = $_[0].
| [reply] [d/l] [select] |
Re: Directory recursion on win32
by talexb (Chancellor) on Aug 04, 2003 at 14:15 UTC
|
I haven't tried your code but it looks OK. There are memory limits to how big an array can grow, but unless you've got a directory structure millions of layers deep, that shouldn't be a problem. Your my ($Variable); declarations suggest that you wrap lists in brackets without knowing why. That will become useful when you write things like
my ( $foo, $bar ) = @_;
since @_ is a list context kind of animal.
How deep did your recursion go? How did it die? What happened? Why do you think it died?
--t. alex
Life is short: get busy!
| [reply] [d/l] [select] |
Re: Directory recursion on win32
by CountZero (Bishop) on Aug 04, 2003 at 18:50 UTC
|
As Mark Jason Dominus so eloquently explained at YAPC::EU in Paris, there is a good case to make to favour non-recursive solutions over recursive solutions for this (type of) problem. He als pointed out some deficiencies in File::Find (which are closely linked to its "recursiveness"). Have a look at his Iterators and constructors article. CountZero Update: Oops, The link only points to the table of contents and not to the slides of this talk itself. I could have sworn that MJD said he would put the slides on his web-site. Wishful thinking on my side probably (or more likely my memory finally giving way). "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law
| [reply] |