Re: recursive dir and file
by xdg (Monsignor) on Nov 11, 2005 at 14:49 UTC
|
When you're recursing, you're passing the name of the subdirectory, but not the full path to it. You either need to concatenate it to the original directory path, or you need to chdir into and out of the subdirectory.
A better alternative may be to use File::Find or File::Find::Rule if those are available to you. Let them manage your recursion and spend your energy writing the code for what you actually want to do with each file.
-xdg
Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.
| [reply] |
Re: recursive dir and file
by Tanktalus (Canon) on Nov 11, 2005 at 14:52 UTC
|
First - you're reusing a global variable DIR. Either localise it before the opendir, or closedir it before the foreach.
Second, the problem with readdir is that you've lost your context. You probably need to do a chdir before you opendir so that when you're looking at $name, you'll be looking at it relative to the requested directory. That's the easy way, although it changes your current working directory for the rest of the script. And you'll need to chdir back after the recursive call to recurse_dir($name).
Or, you could just use File::Find and get all this done for you. Way easier. ;-)
sub recurse_dir {
require File::Find;
File::Find::find(sub {
if (-f $File::Find::name and $File::Find::name =~ /\.sas$/)
{
chmod 0644, $File::Find::name;
print "$File::Find::name has been changed\n";
}
}, @_);
}
(I also took the liberty of achoring your .sas test, and of using perl's built-in chmod function.) | [reply] [d/l] |
Re: recursive dir and file
by tirwhan (Abbot) on Nov 11, 2005 at 15:00 UTC
|
opendir only opens the directory for you, it does not change your current working directory. So you either need to do a chdir before doing any more tests on the files therein or prepend the directory name to the path.
Another possibility would be to use File::Find:
use File::Find;
find (\&change_sas,"/cdw/home_dir/s006258/CSPAM");
sub change_sas {
my $filename=$_;
if (-f $filename && $filename=~m/\.sas\z/) {
chmod 0644,$filename;
print "Found $filename, changing\n";
}
}
Or the *NIX find utility.
find /cdw/home_dir/s006258/CSPAM -name '*.sas' -exec chmod 644 {} \;
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. -- Brian W. Kernighan
| [reply] [d/l] [select] |
|
|
-exec should be avoided. It spawns one process per matched file. In almost every case, you want find -print0 | xargs -r0 instead, which will spawn only one process for as many files as will fit on its command line – usually, that means just one process.
find /cdw/home_dir/s006258/CSPAM -name '*.sas' -print0 | xargs -r0 chm
+od 644
Makeshifts last the longest. | [reply] [d/l] |
|
|
| [reply] |
|
|
Re: recursive dir and file
by blazar (Canon) on Nov 11, 2005 at 15:03 UTC
|
| [reply] |
|
|
Problem is Im running this script on the Unix server and I don't have permission to install any modules. This is the only way I can think of.... Any other solution?
| [reply] |
|
|
| [reply] |
|
|
I really like File::Finder for doing things like this.
As for not being able to install modules you can usually install the module source in your own directory. To install File::Finder you could do the following.
Create a directory named File in the same directory as your script is in.
Download the Finder.pm file from the CPAN link above. (There is a link named "Source" near the top of the page that explains the module.) Save this file in the File directory
At this point you should have a file tree something like:
/home/work/myscript.pl
/home/work/File/Finder.pm
Now when you run your script it should look in the current directory for the modules in addition to the system directories.
| [reply] [d/l] [select] |
|
|
If you're doing this on a unix machine, you don't need perl at all. While File::Find is part of the Perl "core", it is noticeably slower than the unix-native "find" utility. All you need is a unix command line like this:
find /cdw/home_dir/s006258/CSPAM -name '*.sas' -print0 | xargs -0 chmo
+d 644
Note the single-quotes around the '*.sas', to keep the asterisk from being "interpreted" by the shell.
Perl is great, but for little things like this, the shell can be better. | [reply] [d/l] |
Re: recursive dir and file
by aquarium (Curate) on Nov 11, 2005 at 15:02 UTC
|
| [reply] |