【问题标题】:Comparing two directories using Perl使用 Perl 比较两个目录
【发布时间】:2018-04-03 13:15:29
【问题描述】:

我是 Perl 新手,请原谅我的菜鸟,

这就是我打算做的。

$ 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;
        }

在上述代码的帮助下,我无法递归遍历给定目录中的子目录。任何帮助将不胜感激。

编辑:使用 File: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

我正面临测试结果:失败。结果肯定是通过了。有人可以纠正我吗?

谢谢

【问题讨论】:

    标签: perl


    【解决方案1】:

    您使用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】:

      我建议改用File::DirCompare 模块。 ) 它需要遍历目录结构的所有艰苦工作——你只需要定义应该如何检查你的目录(如果 sub 比较文件内容等)

      【讨论】:

      • 我实际上是在尝试模拟 UNIX 的 diff -r 命令是吗?
      【解决方案3】:

      您可能想试试旧版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!。我可以简单地忽略所有不是文件的内容。

      而且,您可能需要检查特殊情况。这是一个链接吗?是硬链接还是软链接?什么类型的特殊文件。这使事情变得更加复杂。但是,基础知识就在这里。

      【讨论】:

        猜你喜欢
        • 2012-03-18
        • 2020-01-18
        • 2023-04-05
        • 2012-10-01
        • 2013-02-19
        • 2018-08-17
        • 2012-03-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多