Сравнение двух каталогов с использованием Perl - PullRequest
1 голос
/ 28 февраля 2012

Я новичок в Perl, так что извините, noobness,

Вот что я собираюсь сделать.

$ perl dirComp.pl dir1 dir2

dir1 & dir2 - это имена каталогов.

Скрипт dirComp.pl должен идентифицировать, является ли содержимое в dir1 и dir2 идентичным или нет.

Я придумал алгоритм

Store all the contents of dir1(recursively) in a list
Store all the contents of dir2 in another list
Compare the two list, if they are same - dir1 & dir2 are same else not.

my @files1 = readdir(DIR1h);
my @files2 = readdir(DIR2h);

    # Remove filename extensions for each list.

        foreach my $item (@files1) {
        my ( $fileName, $filePath, $fileExt ) = fileparse($item, qr/\.[^.]*/);
        $item = $fileName;
        }


        foreach my $item (@files2) {
        my ( $fileName, $filePath, $fileExt ) = fileparse($item, qr/\.[^.]*/);
        $item = $fileName;
        }

Я не могу рекурсивно обходить подкаталоги в данном каталоге с помощью приведенного выше кода. Любая помощь будет оценена.

РЕДАКТИРОВАТЬ: Использование файла: DirCompare

#!/usr/bin/perl -w

use File::DirCompare;
use File::Basename;

if ($#ARGV < 1 )
{
        &usage;
}

my $dir1 = $ARGV[0];
my $dir2 = $ARGV[1];

File::DirCompare->compare($dir1,$dir2,sub {
        my ($a,$b) = @_;
        if ( !$b )
        {
                printf "Test result:PASSED.\n";
                printf "Only in %s : %s\n", dirname($a), basename($a);
        }elsif ( !$a ) {
                printf "Test result:PASSED.\n";
                printf "Only in %s : %s\n", dirname($b), basename($b);
        }else {
                printf "Test result:FAILED.\n";
                printf "Files $a and $b are different.\n";
        }
});

У меня есть структура каталогов, как показано ниже,

dir1/                  dir2/
    --file1.txt            --file1.txt
    --file2.txt            --file2.txt
    --file3.cpp            --file3.cpp

Я столкнулся с результатом теста: FAILED. В результате, должно быть, прошло. Кто-нибудь может поправить меня?

Спасибо

Ответы [ 3 ]

5 голосов
/ 28 февраля 2012

Пример, который вы предоставили, используя File :: DirCompare , работает как задумано.

Имейте в виду, что подпрограмма обратного вызова вызывается для каждого уникального файла в каждом каталогеи для каждой пары файлов , которые отличаются по своему содержанию .Одного и того же имени файла недостаточно, содержимое каждого файла в каждом каталоге также должно быть точно таким же.

Кроме того, случаи, когда вы сообщаете "PASSED", вообще не являются успешными (ваше определение), поскольку они детализируют случаи, когда файл существует в одном из каталогов, но не в другом: это означает, что содержимое каталогов не идентично.

Это должно быть ближе к тому, что вы хотите:

#!/usr/bin/perl

use strict;
use warnings;

use File::DirCompare;
use File::Basename;

sub compare_dirs
{
  my ($dir1, $dir2) = @_;
  my $equal = 1;

  File::DirCompare->compare($dir1, $dir2, sub {
    my ($a,$b) = @_;
    $equal = 0; # if the callback was called even once, the dirs are not equal

    if ( !$b )
    {
      printf "File '%s' only exists in dir '%s'.\n", basename($a), dirname($a);
    }
    elsif ( !$a ) {
      printf "File '%s' only exists in dir '%s'.\n", basename($b), dirname($b);
    }
    else
    {
      printf "File contents for $a and $b are different.\n";
    }
  });

  return $equal;
}

print "Please specify two directory names\n" and exit if (@ARGV < 2);
printf "%s\n", &compare_dirs($ARGV[0], $ARGV[1]) ? 'Test: PASSED' : 'Test: FAILED';
2 голосов
/ 28 февраля 2012

Я бы рекомендовал вместо этого использовать модуль File :: DirCompare .) Требуется вся тяжелая работа по обходу структуры каталогов - вам просто нужно определить, как должны проверяться ваши каталоги (если подпрограмма сравнивает содержимое файла и т. Д.)

0 голосов
/ 29 февраля 2012

Возможно, вы захотите попробовать ol ' File :: Find . Это не мой любимый модуль. (Это просто забавно в том, как это работает), но для ваших целей он позволяет вам легко найти все файлы в двух каталогах и сравнить их. Вот краткий пример:

use strict;
use warnings;
use feature qw(say);
use Digest::MD5::File qw(file_md5_hex);

use File::Find;

use constant {
    DIR_1 => "/usr/foo",
    DIR_2 => "/usr/bar",
};

my %dir_1;
my %dir_2;

find ( sub {
        if ( -f $File::Find::name ) {
            $dir_1{$File::Find::name} = file_md5_hex($File::Find::name);
        }
        else {
            $dir_1($file::Find::name} = "DIRECTORY!";
        }
    }, DIR_1);

find ( sub {
        if ( -f $File::Find::name ) {
            $dir_2{$File::Find::name} = file_md5_hex($File::Find::name);
        }
        else {
            $dir_2($file::Find::name} = "DIRECTORY!";
        }
    }, DIR_2);

Это создаст два хэша с ключами в именах файлов в каждом каталоге. Я использовал Digest :: MD5 :: File для создания контрольной суммы MD5. Если контрольная сумма между двумя файлами различается, я знаю, что файлы различаются (хотя я не знаю, где).

Теперь вам нужно сделать три вещи:

  1. Просмотрите %dir_1 и посмотрите, есть ли эквивалентный ключ в %dir_2. Если нет эквивалентного ключа, вы знаете, что файл существует в %dir_1, а не %dir_2.
  2. Если в каждом хэше есть эквивалентный ключ, проверьте, совпадают ли контрольные суммы md5. Если это так, то файлы совпадают. Если они этого не делают, они отличаются. Вы не можете сказать, где они отличаются, но они отличаются.
  3. Наконец, пройдите %dir_2 и проверьте, есть ли эквивалентный ключ в %dir_1. Если есть, ничего не делать. Если нет, это означает, что в %dir_1 есть файл, которого нет в %dir_2.

Просто предупреждение: ключи этих двух хэшей не будут совпадать . Вам придется преобразовывать одно в другое при выполнении сравнения. Например, у вас будет два файла:

/usr/bar/my/file/is/here.txt
/usr/foo/my/file/is/here.txt

Как видите, my/file/is/here.txt существуют в обоих каталогах, но в моем коде два хэша будут иметь два разных ключа. Вы можете либо исправить две подпрограммы, чтобы убрать имя каталога из передней части путей к файлам, либо, когда вы проводите сравнение, преобразовать одну в другую. Я не хотел проходить полный тест. (Часть кода, которую я написал, работает в моем тестировании), поэтому я не уверен на 100%, что вам нужно сделать, чтобы убедиться, что вы нашли подходящие ключи.

О, еще одно предупреждение: я беру все записи, а не только файлы. Для каталогов я могу проверить, равен ли ключ хеша DIRECTORY! или нет. Я мог бы просто игнорировать все, что не является файлом.

И вы можете проверить наличие особых случаев. Это ссылка? Это жесткая ссылка или мягкая ссылка? Как насчет специального файла . Это делает вещи немного сложнее. Тем не менее, основы здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...