0

フレッド、私が抱えているちょっとした問題でここに戻ってきました。皆さんが私を助けてくれることを願っています。

ここで見つけた古いファイルを調べていて、それを機能させたいと思っていました。ここではもう見つかりませんが、ソースコードがまだ残っているので、別の質問をします。

そこで、彼の課題は次のとおりです。2 つのディレクトリを比較して、通常のファイルの違いを調べる perl スクリプトを作成してください。同じ名前のすべての通常のファイルは、それらが同一であるかどうかを判断する UNIX 関数 /usr/bin/diff -q を使用してテストする必要があります。dir2 に同様の名前のファイルがない dir1 のファイルは、文字列 <<< の後にその名前が出力されますが、対応する dir1 エントリのない dir2 のファイルには、文字列 >>> が前に付けられます。2 つのファイルが同じ名前で異なる場合、ファイル名は > < で囲まれます。

スクリプトは次のとおりです。

#!/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

私はすでにファイルをチェックして、それらがすべて一致していることなどを確認しましたが、まだ問題があります。誰かが私を助けることができれば、私はそれを大いに感謝します!

4

1 に答える 1

3

まず、常にこれらを使用します。

use strict;
use warnings;

学習曲線は短いですが、長期的にはそれを補って余りあるものです。

いくつかのメモ:

  • File::Findシステムコールを使用する代わりに、モジュールを使用する必要があります。
  • 配列インデックス 1 でループを開始します。perl では、最初の配列インデックスは 0 です。したがって、最初の要素をスキップします。
  • ループ条件が間違っています。@files >= $x最大インデックスよりも 1 つ多く反復することを意味します (通常)。$x < @filesまたはのいずれかが必要$x <= $#filesです。
  • chompのより安全なバージョンである を使用する必要がありchopます。
  • 繰り返し処理している配列を変更することは、混乱を招く確実な方法です。
  • なぜif (! -e ...)and then を使用するの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チェックでは、ハッシュに通常のファイルのみが含まれていることが確認されます。

于 2013-03-05T02:02:07.537 に答える