结果:HASH(0x1948958) ARRAY(0x1978250) ./directory/filename
多行
期望结果:[Key of first hash] [Key of second hash] ./directory/filename #(elements of array, currently working)
Catch:应该携带到N层结构,因此我尝试使用Data::Walk。
在遍历结构时,我真正想做的是引用正在使用的键。有点像Data::Dumper,但以制表符分隔,而不是代码格式。我认为可能的解决方案(按优先顺序)是:
- 我忽略了对Data::Walk的调用。
- 一个我不知道的更好的模块。
- 一个可以内联 的快速代码片段
- 我自己的模块/分支Data::Walk/Data::Dumper(大皱眉头),将添加此功能。
use strict;
use File::Basename;
use Data::Walk;
my $files;
while (<>) {
chomp;
#ls -l output in a file; referencing filename from it (8th column)
my @line = split(/ /, $_, 8);
#fileparse exported by File::Basename
my ($name,$path) = fileparse($line[7]);
open (my $fh, '<', $path . $name);
my $sha = Digest::SHA->new('sha1');
$sha->addfile($fh);
#finding files by basename, then unique hash, then however many places it is stored.
#question not why I don't use the hash as the first field.
#basename digest path
push(@{$files->{$name}->{$sha->hexdigest}}, $path . $name);
}
my @val;
sub walkit {
$val[$Data::Walk::depth - 1] = $_;
if ($Data::Walk::depth == 3) {
print join("t", @val), "n";
}
}
&walk (&walkit, %$files);
大师?
编辑:尽管我有更好的判断,我还是试着再回答一次这个问题。
这里有一个简单的方法来打印你想要的东西。使用Data::Walk是不可行的,因为当你在哈希中(你只是得到一个指向容器的指针)时,你没有关键上下文。
这个函数适用于比较复杂的结构。当然,如果你在里面放了一个函数引用或一些不稳定的东西,它不会给出正确的输出。
use strict;
use warnings;
my $res;
sub walk {
my ($item, $path) = @_;
if (ref $item eq 'ARRAY') {
foreach (@$item) {
walk($_, $path);
}
} elsif (ref $item eq 'HASH') {
foreach (keys %$item) {
push @$path, $_;
walk($item->{$_}, $path);
pop @$path;
}
} else {
print join('-', @$path, $item), "n";
}
}
my $struct = {
a => {
a1 => { a11 => [ 1, 2, 3 ] },
a2 => { a22 => [5, 6, 7] }
},
b => { b1 => [ 99 ], },
c => [ 100, 101, ],
d => [ 101, { d2 => { d3 => [200, 210] }, }, ],
};
walk $struct;
for my $name (keys(%$files)) {
for my $digest (keys(%{$files->{$name}})) {
my @qfns = @{ $files->{$name}{$digest} };
if (@qfns > 1) {
say "For $name and $digest,";
say " $_" for @qfns;
}
}
}
(我假设您正在寻找重复项,所以当只有一个路径与名称-摘要组合相关联时,我不打印任何内容。如果您想打印所有内容,可以删除if
。
其他一些清理:
use strict;
use warnings;
use 5.010;
use Digest::SHA qw( );
use File::Basename qw( basename );
sub calc_digest {
my ($qfn) = @_;
open(my $fh, '<', $qfn) or die $!;
my $sha = Digest::SHA->new('sha1');
$sha->addfile($fh);
return $sha->hexdigest();
}
my $files;
while (<>) {
my $qfn = (split)[7];
my $name = basename($path);
my $digest = calc_digest($qfn);
push @{ $files->{$name}{$digest} }, $qfn;
}
("qfn"代表"限定文件名",表示文件的路径,这不是$path
所包含的。即使$line[7]
包含路径,您仍在重复构建路径