Harry Putnam wrote:
> I need to do some matching of filenames in two top level directories.
> We expect to find a number of cases where the endnames ($_) are the
> same in both hierarchies but the full name is different.
>
> base1/my/file
> base2/my/different_path/file
>
> I've made hashes of the file names in two top level directories:
>
> I've assembled the hashes using File::Find. We sort them first by
> matching the base directory to the top directories passed in.
>
> My first impulse wast to do it by matching the endnames (or value) in
> one hash to any matching endname (value) in the other. There are
> several more actions that follow (not coded yet) but That's a lot of
> spinning...
>
> I'm thinking there are better ways to do that. So .. the script below
> does it the hard way, with all that spinning. Can anyone suggest
> another way?
>
> ------- --------- ---=--- --------- --------
> #!/usr/local/bin/perl
>
> use strict;
> use warnings;
>
> use File::Find;
> use Cwd;
>
> my $r1 = shift;
> my $r2 = shift;
( my ( $r1, $r2 ) = @ARGV ) == 2
or die "usage: $0 dir1 dir2\n";
> my %r1h;
> my %r2h;
>
> my $r1hkcn = 0;
> my $r2hkcn = 0;
>
> find(
> sub {
> ## For use in guaranteeing the -f command uses the
> ## right path
> my $dir = getcwd;
The current working directory is already in $File::Find::dir
> if (-f $dir . '/'. $_) {
return unless -f;
> ## Determine if base dir matches r1 or r2
> (my $base) = $File::Find::name =~ m/^(\.*\/*\/[^\/]+)\//;
Instead of all the "leaning toothpicks" use a different delimiter:
(my $base) = $File::Find::name =~ m!^(\.*/*/[^/]+)/!;
> if ($r1 eq $base) {
> $r1h{$File::Find::name} = $_;
> $r1hkcn++;
> if ($r1hkcn == 1) {
> print "v:$File::Find::name k:$_\n";
> }
> } else {
> $r2h{$File::Find::name} = $_;
> $r2hkcn++;
> if ($r2hkcn == 1) {
> print "v:$File::Find::name k:$_\n";
> }
>
> }
> }
> },
> $r1,$r2
> );
>
> my ($r1full,$r1end);
> while (($r1full,$r1end) = each(%r1h)) {
> foreach my $key (keys %r2h) {
No need for a loop there, just use exists():
if ( exists $r2h{ $rlend } ) {
print "$r2h{$rlend} MATCHES $r1end\n";
> if ($r2h{$key} eq $r1end) {
> print "$r2h{$key} MATCHES $r1end\n";
> }
> }
> }
Perhaps you want something like:
#!/usr/local/bin/perl
use strict;
use warnings;
use File::Find;
( my ( $r1, $r2 ) = @ARGV ) == 2
or die "usage: $0 dir1 dir2\n";
my %data;
find sub {
return unless -f;
$data{ $_ }{ $r1 }++;
}, $r1;
find sub {
return unless -f;
$data{ $_ }{ $r2 }++;
}, $r2;
while ( my ( $file, $dir ) = each %data ) {
my @dirs = keys %$dir;
if ( @$dirs == 2 ) {
print "$dirs[0] MATCHES $dirs[1]\n";
}
}
__END__
John
--
The programmer is fighting against the two most
destructive forces in the universe: entropy and
human stupidity. -- Damian Conway
Thread Previous
|
Thread Next