【问题标题】:Compare MD5 from files in a directory against an array (perl)将目录中文件的 MD5 与数组 (perl) 进行比较
【发布时间】:2013-12-25 16:46:43
【问题描述】:

我在这里查看此链接:How could I write a Perl script to calculate the MD5 sum of every file in a directory?

获取指定目录下每个文件的md5。我想要做的是把那些 md5 和一个数组进行比较。这是我目前所拥有的。

use warnings;
use strict;
use Digest::MD5 qw(md5_hex);

my $dirname = "./";
opendir( DIR, $dirname );
my @files = readdir(DIR);
closedir(DIR);

print "@files\n";

foreach my $file (@files) {
    if ( -d $file || !-r $file ) { next; }
    open( my $FILE, $file );
    binmode($FILE);
    print Digest::MD5->new->addfile($FILE)->hexdigest, " $file\n";
    my @array = ('667fc8db8e5519cacbf8f9f2af2e0b08');
        if (@array ~~ $FILE) {
            print "matches array", "\n";
        } else {
            print "doesnt match array", "\n";
    }
}
system ( 'pause' )


但是有了这个,我总是得到不匹配数组,无论它是否完全匹配数组。我可以print @array,它甚至会显示文件的相同 md5 值。但就像我说的那样,它总是说“不匹配数组”。我从来没有在任何文件上说“匹配数组”。感谢您的关注:)

编辑: 这就是我现在所拥有的。

use warnings;
use strict;
use Digest::MD5 qw(md5_hex);

my $dirname = "./";
opendir( DIR, $dirname );
my @files = readdir(DIR);
closedir(DIR);

print "@files\n";

foreach my $file (@files) {
    next if -d $file || !-r $file;
    open( my $FILE, $file );
    binmode($FILE);
    #print digest::MD5->new->addfile($FILE)->hexdigest, " $file\n";
    Sdigest = Digest::MD5->new->addfile($FILE)->hexdigest, " $file\n";

    my @array = ('667fc8db8e5519cacbf8f9f2af2e0b08');
        if($digest eq $array[0]) {
            print "matches array", "\n";
        } else {
            print "doesnt match array", "\n";
    }
}
system ( 'pause' );


感谢大家的帮助。你们太棒了;)

【问题讨论】:

  • 修正格式。用奇怪的缩进很难说出这里发生了什么。
  • 好吧,我现在就这么做。谢谢
  • 确定要匹配数​​组的第一个元素吗? $array[0]
  • 您希望将十六进制摘要匹配到数组的第一个元素,而您将文件句柄匹配到整个数组。
  • 为什么你需要一个数组,当你只有一个你有兴趣比较的值时?

标签: arrays perl directory compare md5


【解决方案1】:

请不要使用智能匹配~~。它在最新版本的 Perl 中被宣布为实验性的,未来语义可能会发生变化。

最好的解决方案是创建你知道的指纹的哈希:

my %fingerprints;
$fingerprints{"667fc8db8e5519cacbf8f9f2af2e0b08"} = undef;

如果您想将整个指纹数组加载到哈希中以便我们可以轻松测试是否存在,您可以使用哈希切片

@fingerprints{@array} = ();

接下来,我们将当前文件的指纹存储在一个变量中:

my $digest = Digest::MD5->new->addfile($FILE)->hexdigest;

然后我们测试$digest是否存在于指纹哈希中:

if (exists $fingerprints{$digest}) {
  print "$digest for <$file> -- FOUND\n";
}
else {
  print "$digest for <$file>\n";
}

使用散列通常比遍历数组更快(如果您进行多次查找)。


建议的完整程序:

use strict;
use warnings;
use feature qw< say >;
use autodie;  # automatic error handling
use Digest::MD5;

my ($dirname, $fingerprint_file) = @ARGV; # takes two command line arguments
length $dirname          or die "First argument must be a directory name\n";
length $fingerprint_file or die "Second argument must be a file with fingerprints\n";

# load the fingerprints
my %fingerprints;
open my $fingerprints_fh, "<", $fingerprint_file;
while (<$fingerprints_fh>) {
  chomp;
  $fingerprints{$_} = undef;
}
close $fingerprints_fh;

opendir my $directory, $dirname;
while(my $file = readdir $directory) {
  next if not -f $file;

  open my $fh, "<:raw", "$dirname/$file";
  my $digest = Digest::MD5->new->addfile($fh)->hexdigest;
  close $fh;

  if (exists $fingerprints{$digest}) {
    say qq($digest "$file" -- FOUND);
  }
  else {
    say qq($digest "$file");
  }
}
closedir $directory;

示例调用

> perl script.pl . digests.txt

【讨论】:

  • 这也有效。尽管所有答案都有效,但老实说,这可能是我的情况。因为我可以更新 digests.txt 文件,所以我不必不断更新脚本。只是 .txt 文件。谢谢:)
  • 如果我尝试指定“script.pl C:/Users/Username/Desktop/check this/C:/digests/digests”,则无法指定文件路径,除非它们位于同一目录“./”中。 txt”它完成没有错误,但它不输出任何东西。我尝试在目录路径中使用“/”和“//”和“\\”。
  • 我很想将此添加到右键单击上下文菜单中。我可以把它变成exe。我只是在尝试运行它时出错,因为我无法在脚本中指定路径。
  • @james28909 真傻,我忘了readdir 只返回文件名,而不是路径。我做了一个快速修复(尽管这不是正确的方法)。因为脚本需要参数,所以您应该通过命令行运行它。我不知道如何在上下文菜单中添加一个条目,并能够为脚本提供正确的参数。
【解决方案2】:

也许以下内容会有所帮助:

use warnings;
use strict;
use Digest::MD5 qw(md5_hex);
use File::Basename;

my $dirname = './';
my %MD5s    = (
    '667fc8db8e5519cacbf8f9f2af2e0b08' => 1,
    '8c0452b597bc2c261ded598a65b043b9' => 1
);

for my $file ( grep { !-d and -r } <$dirname*> ) {
    open my $FILE, '<', $file or die $!;
    binmode $FILE;
    my $md5hexdigest = Digest::MD5->new->addfile($FILE)->hexdigest;
    close $FILE;

    print basename ($file), " md5hexdigest $md5hexdigest ";

    if ( $MD5s{$md5hexdigest} ) {
        print "matches hash", "\n";
    }
    else {
        print "doesn't match hash", "\n";
    }
}

样本输出:

XOR_String_Match.pl md5hexdigest 8c0452b597bc2c261ded598a65b043b9 matches hash
zipped.txt md5hexdigest d41d8cd98f00b204e9800998ecf8427e doesn't match hash

【讨论】:

  • 这很好用。所以哈希比数组更好用?还是仅针对此特定实例?
  • @james28909 如果元素的顺序不重要,散列是好的。他们使用一种特殊的数据结构,可以非常快速地找到一个元素。
【解决方案3】:

像这样:

my $digest = Digest::MD5->new->addfile($FILE)->hexdigest, " $file\n";

然后

if($digest eq $array[0])

顺便说一句,说起来可能会更习惯一些(在你的代码前面):

next if -d $file || !-r $file;

【讨论】:

  • 谢谢 :-) 已更正。
  • 过多的 bash 会害死你。
  • 无法通过包“digest::MD5”定位对象方法“new”(也许您忘记加载“digest::MD5”。我刚刚尝试了 ppm 和 cpan,但找不到 Sdigest: :MD5。我厌倦了使用 Sdigest::MD5 qw(md5_hex); 但它失败并显示相同的错误消息。
  • 我还要再说一遍,我将比较大约 25 个 MD5 ($FILE) 和大约 1600 个 MD5 (@array)
猜你喜欢
  • 1970-01-01
  • 2015-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多