Newbie Question...

E

EddieJ

I'm writing my first perl script and I'm running in to
difficulties as I imagined. What I'm trying to do is
basically scan all the directories and subdirectories
of a drive for powerpoint files, write the full path
and name of the files to an ordinary text file, and
then remove the drive name and colon (eg C:) from the
path and send the output to another text file.

The script I have so far is...

print "Which drive do you want to search? ";
chomp($drive = <STDIN>);
chdir("$drive") || die "Cannot access requested drive";
$outputfile1 = ("%HOMEDRIVE%\\ppfile1.txt");
$outputfile2 = ("%HOMEDRIVE%\\ppfile2.txt");
$outputfile3 = ("%HOMEDRIVE%\\ppfile3.txt");

if (-e $outputfile1) {
unlink ($outputfile1);
}

if (-e $outputfile2) {
unlink ($outputfile2);
}

if (-e $outputfile3) {
unlink ($outputfile3);
}
system ("dir/s/b *.pp* >$outputfile1") && die "Cannot write to file1 $!";
system ("dir/s/b *.xyz >$outputfile2");
open FILE1, ">$outputfile1" || die "Cannot open file1 $!";
open FILE2, ">$outputfile2" || die "Cannot open file2 $!";
while (defined <FILE1>) {
# print FILE1 $_;
print FILE2 s/^a-zA-Z://;
}
close (FILE1) || die "Cannot close file1 $!";
close (FILE2) || die "Cannot close file2 $!";

But when I run it, the second output file is empty and perl
complains that it cannot close the first outputfile

-----------------------------
Which drive do you want to search? j:
File Not Found
Cannot close file1 Bad file descriptor at powerp.pl line 27.
-------------------------------

The "File Not Found" is from the
"system ("dir/s/b *.xyz >$outputfile2");"
which doesnt bother me since I'm just trying to create an empty
file so that I can open it later to receive the output (without
the C:).

From what I can see though, the open commands aren't working
despite the use of the "die" commands..


So...I'm sure this is very obvious to anyone with experience
of Perl, but (a) what am I doing wrong with the script??? and
(b) is there a more efficient way of doing what I'm trying to
do??. Can you do a recursive directory search in perl without
using the system dir/b/s command, and should I store the output
in an array rather than the first output file....

Thanks in advance....

EJ
 
P

Paul Lalli

I'm writing my first perl script and I'm running in to
difficulties as I imagined. What I'm trying to do is
basically scan all the directories and subdirectories
of a drive for powerpoint files, write the full path
and name of the files to an ordinary text file, and
then remove the drive name and colon (eg C:) from the
path and send the output to another text file.

The script I have so far is...

#!perl.exe
use warnings;
use strict;

print "Which drive do you want to search? ";
chomp($drive = <STDIN>);
chdir("$drive") || die "Cannot access requested drive";
$outputfile1 = ("%HOMEDRIVE%\\ppfile1.txt");
$outputfile2 = ("%HOMEDRIVE%\\ppfile2.txt");
$outputfile3 = ("%HOMEDRIVE%\\ppfile3.txt");

if (-e $outputfile1) {
unlink ($outputfile1);
}

if (-e $outputfile2) {
unlink ($outputfile2);
}

if (-e $outputfile3) {
unlink ($outputfile3);
}

Why are you bothering with this? If the files exist when you try to open
them for writing, they are automatically clobbered.
system ("dir/s/b *.pp* >$outputfile1") && die "Cannot write to file1 $!";
system ("dir/s/b *.xyz >$outputfile2");

Good checking the return value of the first system(). Bad not checking
the return value of the second system().
open FILE1, ">$outputfile1" || die "Cannot open file1 $!";
open FILE2, ">$outputfile2" || die "Cannot open file2 $!";
while (defined <FILE1>) {
# print FILE1 $_;
print FILE2 s/^a-zA-Z://;
}

What? What exactly are you trying to do here? You're opening two files
for writing, and then trying to read from one of them, and exit the loop
when you can't read any more. This doesn't make sense. You can't read
from FILE1 because you opened FILE1 for writing.

I don't understand what data you're expecting to be in $_. I also don't
understand why you're trying to open these files at all when you already
redirected the output of the system() calls to go to those files.
close (FILE1) || die "Cannot close file1 $!";
close (FILE2) || die "Cannot close file2 $!";

But when I run it, the second output file is empty and perl
complains that it cannot close the first outputfile

-----------------------------
Which drive do you want to search? j:
File Not Found
Cannot close file1 Bad file descriptor at powerp.pl line 27.
-------------------------------

The "File Not Found" is from the
"system ("dir/s/b *.xyz >$outputfile2");"
which doesnt bother me since I'm just trying to create an empty
file so that I can open it later to receive the output (without
the C:).

From what I can see though, the open commands aren't working
despite the use of the "die" commands..


So...I'm sure this is very obvious to anyone with experience
of Perl, but (a) what am I doing wrong with the script??? and
(b) is there a more efficient way of doing what I'm trying to
do??. Can you do a recursive directory search in perl without
using the system dir/b/s command, and should I store the output
in an array rather than the first output file....


To answer b) "Yes, use File::Find". This is a module that will
recursively scan any directory you give to it. For more info,
perldoc File::Find

#!perl.exe
use strict;
use warnings;
use File::Find;

my $dir = "C:";
my ($out1, $out2);
open $out1, "> output1.txt" or die "Cannot open output1.txt: $!";
open $out2, "> output2.txt" or die "Cannot open output2.txt: $!";


sub wanted {
return unless /\.ppt$/i; #skip non-powerpoint files
print $out1 "$File::Find::name\n"; #print full path to one file
$File::Find::name =~ s/^[a-z]://i; #strip C:
print $out2 "$File::Find::name\n"; #print modified path to other
}

find (\&wanted, $dir); #recursively scan all directories under C:
__END__


Hope this helps
Paul Lalli
 
D

David K. Wall

Please put the subject of your post in the Subject header of your
post. "Newbie Question" is not very informative.


EddieJ said:
So...I'm sure this is very obvious to anyone with experience
of Perl, but (a) what am I doing wrong with the script???

Using DOS commands when there are easier ways to do much more with
Perl. :)
and
(b) is there a more efficient way of doing what I'm trying to
do??. Can you do a recursive directory search in perl without
using the system dir/b/s command,

Yes. See File::Find.

# example untested code
use strict;
use warnings;
use File::Find;

my $drive = 'c';
find(
sub{
if (/\.pp.$/) {
(my $path = $File::Find::name) =~ s/^$drive://;
print "$path\n";
}
},
"$drive:/"
);
and should I store the output
in an array rather than the first output file....

I don't know. What are you intending to do with the data after you
collect it?
 
J

J. Gleixner

EddieJ said:
So...I'm sure this is very obvious to anyone with experience
of Perl, but (a) what am I doing wrong with the script??? and

Your most pressing issue is with the open.

system ("dir/s/b *.pp* >$outputfile1") && die "Cannot write to file1 $!";
open FILE1, ">$outputfile1" || die "Cannot open file1 $!";

The "open" is opening ( > ) $ouptputfile1 for a write, which removes any
data already in that file. You want "<" to read from that file.

For reference:

perldoc perlopentut

(b) is there a more efficient way of doing what I'm trying to
do??. Can you do a recursive directory search in perl without
using the system dir/b/s command, and should I store the output
in an array rather than the first output file....

Yes and Yes. Take a look at File::Find

http://search.cpan.org/~lbrocard/perl5.005_04/lib/File/Find.pm

Only write it to a file if there's a lot of data, which would use more
memory than your machine can handle. If you can keep the info in an
array, make your modifications to it then write it to disk or do
whatever you need, it'll be much better.

See ya
 
G

Glenn Jackman

EddieJ said:
$outputfile1 = ("%HOMEDRIVE%\\ppfile1.txt");

I don't have Perl on a windows box, but you probably want:
my $file = "$ENV{HOMEDRIVE}\\ppfile1.txt";
 
P

Paul Lalli

open FILE1, ">$outputfile1" || die "Cannot open file1 $!";
open FILE2, ">$outputfile2" || die "Cannot open file2 $!";

BTW, a possible reason your opens are failing is that you're using the
wrong form of 'or'. The two operators 'or' and '||' have the same effect,
but at a different precedence. Specifically, || binds more tightly than
the open operator, so die was never getting called. Your two options are
either:

open FILE1, "> $outputfile1" or die "Cannot open file1: $!";
or
open (FILE1, "> $outputfile") || die ("Cannot open file1: $!");

while (defined <FILE1>) {
# print FILE1 $_;
print FILE2 s/^a-zA-Z://;
}

In addition to what I said in my last message, it might not be a bad idea
for you to review regular expressions. Printing the result of a
search-and-replace is not going to give you what you think it is for one,
and a-zA-Z doesn't mean what you think it does without being in a
character class.

perldoc perlre
So...I'm sure this is very obvious to anyone with experience
of Perl, but (a) what am I doing wrong with the script??? and
(b) is there a more efficient way of doing what I'm trying to
do??. Can you do a recursive directory search in perl without
using the system dir/b/s command, and should I store the output
in an array rather than the first output file....

Reading this one more time, I think I misunderstood you the first time
around. If you don't actually need the "full" pathname (with C:)
attached, remove the lines that deal with the first input file from the
code I posted in the previous message. Instead:

#!perl.exe
use strict;
use warnings;
use File::Find;

my $dir = "C:";
my $out;
open $out, "> output.txt" or die "Cannot open output1.txt: $!";

sub wanted {
return unless /\.ppt$/i; #skip non-powerpoint files

$File::Find::name =~ s/^[a-z]://i; #strip C:
print $out "$File::Find::name\n"; #print modified path to file
}

find (\&wanted, $dir); #recursively scan all directories under C:
__END__


Paul Lalli
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,141
Messages
2,570,817
Members
47,362
Latest member
ChandaWagn

Latest Threads

Top