如何比较perl中的两个目录及其文件
问题描述:
Fred再次遇到一个小问题,我希望你们能帮助我。如何比较perl中的两个目录及其文件
我在审查midterms,并通过我在这里找到的旧文件,我想让它工作。我在这里找不到它,但我仍然有源代码,所以我会提出另一个问题。
所以这里是他的任务: 编写一个Perl脚本,将比较两个目录中的常规文件的差异。所有具有相同名称的常规文件应该使用unix函数/ usr/bin/diff -q进行测试,这将确定它们是否相同。 dir1中没有类似命名文件的dir2中的文件将在字符串< < <之后打印名称,而dir2中没有相应dir1条目的文件将以字符串>>>作为前缀。如果两个文件具有相同的名称但不同,则文件名将被> <包围。
下面是脚本:
#!/usr/bin/perl -w
use File::Basename;
@files1 = `/usr/bin/find $ARGV[0] -print`;
chop @files1;
@files2 = `/usr/bin/find $ARGV[1] -print`;
chop @files2;
statement:
for ($i=1; @files1 >= $i; $i++) {
for ($x=1; @files2 >= $x; $x++) {
$file1 = basename($files1[$i]);
$file2 = basename($files2[$x]);
if ($file1 eq $file2) {
shift @files1;
shift @files2;
$result = `/usr/bin/diff -q $files1[$i] $files2[$x]`;
chop $result;
if ($result eq "Files $files1[$i] and $files2[$x] differ") {
print "< $file1 >\n";
next statement;
} else {
print "> $file1 <\n";
}
} else {
if (!-e "$files1[$i]/$file2") { print ">>> $file2\n";}
unless (-e "$files2[$x]/$file1") { print "<<< $file1\n";}
}
}
}
这是输出:
> file2 <
>>> file5
<<< file1
输出应该是:
> file1 <
> file2 <
<<< file4
>>> file5
我已经检查了文件,以确保它们所有匹配,但仍然有问题。如果有人能帮助我,我将不胜感激!
答
首先,始终使用这些:
use strict;
use warnings;
它配备了一个简短的学习曲线,但他们比弥补它在长期运行。
一些注意事项:
- 您应该使用
File::Find
模块,而不是使用系统调用。 - 您在数组索引1处开始循环。在perl中,第一个数组索引为0.因此您跳过第一个元素。
- 您的循环条件错误。
@files >= $x
表示您将迭代到比最大索引多1个(通常)。您需要$x < @files
或$x <= $#files
。 - 您应该使用
chomp
,这是一个更安全的chop
版本。 - 改变你正在迭代的数组是一个肯定的方式,让你自己有些困惑。
- 为什么要用
if (! -e ...)
然后unless (-e ...)
?这肯定会增加混乱。
而且这一部分:
$file1 = basename($files1[$i]);
...
if (!-e "$files1[$i]/$file2")
假设@files1
包含文件名,而不仅仅是目录,这将永远不会匹配任何内容。例如:
$file2 = basename("dir/bar.html");
$file1 = basename("foo/bar.html");
-e "foo/bar.html/bar.html"; # does not compute
我会建议使用哈希值进行查找,假设你只是要匹配相同的文件名和丢失的文件名:
use strict;
use warnings;
use File::Find;
use List::MoreUtils qw(uniq);
my (%files1, %files2);
my ($dir1, $dir2) = @ARGV;
find(sub { -f && $files1{$_} = $File::Find::name }, $dir1);
find(sub { -f && $files2{$_} = $File::Find::name }, $dir2);
my @all = uniq(keys %files1, keys %files2);
for my $file (@all) {
my $result;
if ($files1{$file} && $files2{$file}) { # file exists in both dirs
$result = qx(/usr/bin/diff -q $files1{$file} $files2{$file});
# ... etc
} elsif ($files1{$file}) { # file only exists in dir1
} else { # file only exists in dir2
}
}
在find()
子程序,$_
代表基本名称,并且$File::Find::name
包含路径的名称(适用于diff
)。 -f
检查将断言您只在散列中包含常规文件。