如何比较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检查将断言您只在散列中包含常规文件。