On Thu, Dec 29, 2011 at 5:08 PM, Igor Dovgiy <ivd.pri...@gmail.com> wrote:

> Hi Jonathan,
>
> Let's review your script a bit, shall we? )
> It's definitely good for a starter, but still has some rough places.
>
>  #!/usr/bin/perl
>> # md5-test.plx
>> use warnings;
>> use strict;
>>
> use File::Find;
>>
> use Digest::MD5;
>> use File::Spec;
>>
> So far, so good. )
>
>
>> my $dir = shift || '/Users/jonharris/Documents/begperl';
>>
>  Nice touch, setting up a default param. ) The name of variable might seem
> too generic to some, but then again, it's the only directory we deal with,
> so...
>
>
>> my ($dircontents, $path, @directory, $fh, $wr_fh);
>>
> Incoming!
>
> Well, it's usually better to declare your variables right before you'll
> really need them...
> Your script is short, so you'll hardly have a chance to forget what $fh
> and $wr_fh mean, though. )
>
>
>> @directory = $dir;
>> $path = File::Spec->catfile( @directory, $dircontents );
>>
> Ahem. At least three 'wtf' moments for me. )
> First of all, File::Spec->catfile is really just a glorified join operator
> with some additional operations depending on which system you're using.
> So, second, it makes a little sense to convert $dir into @directory
> (documentation example is just that, an example) and to pass there
> undefined $dircontents as well.
> But the major one is why you'd ever have to pass your $dir through
> File::Spec? It's, you know, user input... )
>
> opendir (my $in, $path) or die "Cannot open $dir: $!\n";
>>
> So you're trying to open $path, but warn about failure to open $dir? )
> But then again, that's a minor quarrel, considering this:
>
>
>> find (\&wanted, $path);
>>
> See, File::Find is convenient method which _emulates_ the whole
> opendir-readdir-closedir pattern for a given directory.
> The 'wanted' subroutine (passed by ref) will be called for each file found
> in $path.
> It's described really well in perldoc (perldoc File::Find).
>
> close $in;
>>
> Opendir, but close - and not closedir? Now I'm confused. )
>
> opendir (my $totalin, $path) or die "Cannot open $dir: $!\n";
>> find (\&cleanup, $path);
>> close $totalin;
>>
> You don't have to use different variable to store temporary file handle
> (which will be closed in three lines) - and that will save you a few
> moments spent working out a new (but rational) name for it. :)
> But then again, you don't need to open the same dir twice: you can call
> cleanup (with the same 'find (\&cleanup)... ' syntax) whenever you want.
> And you don't really need cleanup... whoops, going too far too soon. :)
>
> print "\n\nAll Done!\n\n";
>>
>
>> sub wanted {
>> while ($dircontents = readdir($in)) {
>>
> Did I say that you're using two alternative methods of doing the same
> thing? )
> But there's another big 'no-no' here: you're using external variable
> ($dircontents) when you really have perfectly zero reasons to do so.
> Of course, you don't need to push dirhandle ($in) from outer scape into
> this sub, when using find... ($File::Find::dir will do), but that's
> explainable at least. )
>
>  if ($dircontents=~/^\./ || -d $dircontents) {
>> next;
>> }
>>
> So now the script ignores all the files which names begin with '.', and
> you really wanted just to ignore '.' and '..' ... )
>
>  my $bytes = -s $dircontents;
>>
>  print $dircontents, "\n";
>> print $bytes, " bytes", "\tSo far so good!\n";
>>
> Yes. )
>
>>  open $fh, "<", "$dircontents" or die $!;
>> open $wr_fh, "+>", "$path $dircontents.md5" or die $!;  ## was unable to
>> concatenate here, hence sub cleanup to remove the ' '
>>
> What was wrong with ...
> open my $wr_fh, '>', File::Spec->catfile($path, $dircontents, '.md5') or
> die $!, $/
> ?
>
>>
>> my $hex = Digest::MD5->new->addfile($fh)->hex digest;
>> print "Hex Digest: ", $hex, "\n\n";
>>  print $wr_fh $hex, "\n", $bytes, "\n\n";
>>
> All looks great for now: you're calculating md5 and size, and writing it
> into file with md5 extension...
>
>> return($hex);
>>
> ... but now you're abruptly jumping out of the while block, making the
> whole point of cycle, well, completely pointless. Not great.
>
>> close $wr_fh;
>> close $fh;
>>
> }
>> }
>>
>
>
>>
>> # The following is mostly not original code - thanks to the author!
>>
> sub cleanup {
>> my @filelist = readdir($totalin);
>>  foreach my $oldname (@filelist) {
>> next if -d $oldname;
>> my $newname = $oldname;
>>  $newname =~ s/\ //;
>>
> So you don't have spaces in your filenames. Great for you. )
>
>>  rename $oldname, $newname;
>> }
>> }
>>
>>
> ##### End #####
>>
>>
> And here we finish.
>
> Computers are not smart. They're dumb. But they're fast. And obedient. )
> That's why they're really helpful in letting you do what you're trying to
> do... but only if you KNOW what you're trying to do.
>
> Imagine that you're - and not your computer - will be doing this task.
> Sit in one place - and write down your program as you (and not your
> computer) will be running it. Step by step. Bit by bit.
>
> Then convert your notes into some Perl form - and you'll instantly see the
> difference between now and then. )
>
> -- iD
>

Hi Igor

Many thanks for your response

I have started reviewing the things you said
There are some silly mistakes in there - eg not using closedir
It's a good lesson in script vigilance

I found the part about opening the file handle particularly interesting
I had no idea that

open my $wr_fh, '>', File::Spec->catfile($path, $dircontents, '.md5') or
die $!, $/

was possible

Now it's time to sit down and digest all this......and rewrite the script
to make it better!

Many thanks for your advice and Happy New Year

Jonathan

Reply via email to