如何比较两个目录及其在perl中的文件 [英] How to compare two directories and their files in perl

查看:128
本文介绍了如何比较两个目录及其在perl中的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我正在审查中期,并审查一个老的文件我在这里发现,我想让它工作。我不能在这里找到它,但我仍然有源代码,所以我会提出另一个问题。



这是他的任务:
编写一个perl脚本,它将比较两个目录中常规文件中的差异。所有具有相同名称的常规文件应该使用unix函数/ usr / bin / diff -q进行测试,这将确定它们是否相同。在dir1中没有类似命名的文件的文件将在字符串<<<而dir2中没有相应dir1条目的文件将以字符串>>>作为前缀。如果两个文件具有相同的名称但不同,则文件名将被><。



以下是脚本:

 #!/ usr / bin / perl -w 
使用File :: Basename;

@ files1 =`/ usr / bin / find $ ARGV [0] -print`;
chop @ files1;
@ files2 =`/ usr / bin / find $ ARGV [1] -print`;
chop @ files2;

语句:
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 eqFiles $ files1 [$ i]和$ files2 [$ x] different){
print< $ file1> \\\
;
next语句;
} else {
print> $ file1< \\\
;
}
} else {
if(!-e$ files1 [$ i] / $ file2){print>>> $ file2\\\
;}
unless(-e$ files2 [$ x] / $ file1){print<<< $ file1\\\
;}
}
}
}

这是输出:

 > file2< 
>>>> file5
<<< file1

输出应为:

 > file1< 
> file2<
<<< file4
>>>> file5

我已经检查了文件,以确保它们都匹配,但仍然有问题。

解决方案

首先,请务必使用这些:

 使用strict; 
使用警告;

它有一个简短的学习曲线,但它们远远弥补了它的长期。



一些备注:




  • 您应该使用 File :: Find 模块,而不是使用系统呼叫。

  • 在数组索引1处启动循环。在perl中,第一个数组索引为0.因此,跳过第一个元素。

  • 您的循环条件错误。 @files> = $ x 表示您将迭代到超过max索引(通常)。你想要 $ x< @files $ x< = $#files

  • c> 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);
-efoo / bar.html / bar.html; #不计算






查找,假设您只想匹配相同的文件名和缺少的文件名:

  use strict; 
使用警告;
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);

为我的$文件(@all){
my $ result;
if($ files1 {$ file}&& $ files2 {$ file}){#文件存在于两个dirs中
$ result = qx(/ usr / bin / diff -q $ files1 { $ file} $ files2 {$ file});
#... etc
} elsif($ files1 {$ file}){#文件只存在于dir1
} else {#文件只存在于dir2
}
}

子程序 $ _ 代表基本名称, $ File :: Find :: name 适用于 diff )。 -f 检查将断言您只将常规文件包含在哈希中。


Fred here again with a little issue I'm having that I hope you guys can help me with.

I'm reviewing for midterms and going over an old file I found on here and I wanted to get it working. I can't find it on here anymore but I still have the source code so I'll make another question on it.

So here was his assignment: Write a perl script that will compare two directories for differences in regular files. All regular files with the same names should be tested with the unix function /usr/bin/diff -q which will determine whether they are identical. A file in dir1 which does not have a similarly named file in dir2 will have it's name printed after the string <<< while a file in dir2 without a corresponding dir1 entry will be prefixed with the string >>>. If two files have the same name but are different then the file name will be surrounded by > <.

Here is the script:

#!/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";}
        }
    }
}

This is the output:

> file2 <
>>> file5
<<< file1

The output should be:

> file1 <
> file2 <
<<< file4
>>> file5

I already checked the files to make sure that they all match and such but still having problems. If anyone can help me out I would greatly appreciate it!

解决方案

First off, always use these:

use strict;
use warnings;

It comes with a short learning curve, but they more than make up for it in the long run.

Some notes:

  • You should use the File::Find module instead of using a system call.
  • You start your loops at array index 1. In perl, the first array index is 0. So you skip the first element.
  • Your loop condition is wrong. @files >= $x means you will iterate to 1 more than max index (normally). You want either $x < @files or $x <= $#files.
  • You should use chomp, which is a safer version of chop.
  • Altering the arrays you are iterating over is a sure way to cause yourself some confusion.
  • Why use if (! -e ...) and then unless (-e ...)? That surely just adds confusion.

And this part:

$file1 = basename($files1[$i]);
...
if ( !-e "$files1[$i]/$file2" )

Assuming @files1 contains file names and not just directories, this will never match anything. For example:

$file2 = basename("dir/bar.html");
$file1 = basename("foo/bar.html"); 
-e "foo/bar.html/bar.html";         # does not compute


I would recommend using hashes for the lookup, assuming you only want to match against identical file names and missing file names:

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

In the find() subroutine, $_ represents the base name, and $File::Find::name the name including path (which is suitable for use with diff). The -f check will assert that you only include regular files in your hash.

这篇关于如何比较两个目录及其在perl中的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆