heidi has asked for the wisdom of the Perl Monks concerning the following question:
Am a beginner in perl, i have a list of names of text files('one.txt','two.txt','three.txt') in an array called @files. these files and its contents along with other text files are already in a folder called "old". i want to check whether the file names which i have in the array @files are present in the "old" folder, and if present, i have to copy those files to a newfolder called "new". i have no idea how to do this.
Re: writtings files to a new folder
by gaal (Parson) on Jan 24, 2007 at 06:05 UTC
|
To move a file, use the File::Copy module, but make sure the move worked by looking at the return value. To check if a file exists somewhere, use the -f FILENAME builtin. To go over all the files, use for. Putting it all together:
use File::Copy;
our $VERBOSE = 1; # turn this off if you don't need the verbose messag
+es
for my $file (@files) {
if (-f "old/$file") {
print "old/$file -> new/$file\n" if $VERBOSE;
move("old/$file", "new/.") or die "move: old/$file: $!";
}
}
Note that if this encounters an error, it'll stop in the middle. Maybe in your application it's more right to push the erring filename to a @failed array and then print them all, retry, whatever. I don't know; it's just something to think about.
Also, I've assumed "/" is a correct filepath separator and in most cases it is, but if you want to write really portable code you'll want to look into File::Spec. | [reply] [d/l] [select] |
|
Also, I've assumed "/" is a correct filepath separator and in most cases it is, but if you want to write really portable code you'll want to look into File::Spec.
That's not the complete picture, as non-Unix operating systems support POSIX syntax (i.e. Unix) besides their own native syntax. All operating systems that run perl support POSIX syntax, otherwise the perl build process wouldn't work. For a bizarre native syntax, have a look at VMS. There can be problems if you try and mix native and POSIX, though sometimes in Windows, you can get away with a mixture of slashes leaning both ways.
My advice is to either stick to native syntax, with File::Spec and friends, or use POSIX syntax throughout. Beware that a user supplied filename might contain native syntax elements.
For more on this, and portability in general, please refer to my talk slides - I have given this talk at several YAPCs.
--
Oh Lord, won’t you burn me a Knoppix CD ?
My friends all rate Windows, I must disagree.
Your powers of persuasion will set them all free,
So oh Lord, won’t you burn me a Knoppix CD ? (Missquoting Janis Joplin)
| [reply] |
Re: writtings files to a new folder
by siva kumar (Pilgrim) on Jan 24, 2007 at 09:12 UTC
|
Hope below code may help you.
Create the directory 'new' before running the script.
#!/usr/bin/perl
use strict;
use File::Copy;
my @files = ('one.txt','two.txt','three.txt');
for my $file (@files) {
if (-f "old/$file") {
print "old/$file moved to new/$file\n" ;
copy("old/$file", "new/.") or die "Error Coping /old/$file: $!
+";
}
}
| [reply] [d/l] |
Re: writtings files to a new folder
by MaxKlokan (Monk) on Jan 24, 2007 at 09:40 UTC
|
For a beginner my solution is perhaps too cryptic, but I am going to give it anyway, just in case somebody finds it interesting.
You can do it all with a single command if you use grep, which can be used to apply a block of statements to all elements in a list :
use File::Copy;
grep { (move("old/$_", "new/.") or warn "$_ => $!") if -f } @files;
The default variable $_ is set to each element of the list and the operator -f can work with it.
$! is the error message if an error has indeed occurred. | [reply] [d/l] |
|
If you're going to use dense loop constructs like this, 'map' is a slightly better choice than grep for expressing your intentions. Or probably even better:
do { some; series of; commands; which can use $_; } foreach @files;
But this is only if you have an aversion to newlines (which I can relate to), since this clearly the same as:
foreach (@files) {
some;
series of;
commands;
which can use $_;
}
| [reply] [d/l] [select] |
|
Thinking of it, I myself would probably use do {...} foreach @list; as you suggest, because I find it more readable. At first I found that particular use of grep intriguing. Then again, I wonder whether it was a good idea to add such a (potentially confusing) functionality to grep, since foreach works perfectly fine.
| [reply] [d/l] |
|
|
|
|