1

私はまだPerlを学んでいます。.tar.gz のファイルとディレクトリ パスを比較するための Perl コードを教えてください。

数日前に取得した次のディレクトリ パスの tar.gz バックアップがあるとします。

a/file1
a/file2
a/file3
a/b/file4
a/b/file5
a/c/file5
a/b/d/file and so on..

ここで、このパスの下にあるファイルとディレクトリを tar.gz バックアップ ファイルと比較したいと思います。

そのための Perl コードを提案してください。

4

5 に答える 5

5

Archive::Tarを参照してください。

于 2009-08-13T13:51:25.463 に答える
5

とモジュールが役に立ちますArchive::TarFile::Find基本的な例を以下に示します。tar 内のファイルとディレクトリ ツリー内のファイルに関する情報を出力するだけです。

ファイルをどのように比較したいのか、あなたの質問からは明確ではありませんでした。実際のコンテンツを比較する必要がある場合は、get_content()メソッド inArchive::Tar::Fileが必要になる可能性があります。単純な比較 (名前、サイズ、mtime など) で十分な場合は、以下の例で使用されているメソッド以上のものは必要ありません。

#!/usr/bin/perl
use strict;
use warnings;

# A utility function to display our results.
sub Print_file_info {
    print map("$_\n", @_), "\n";
}

# Print some basic information about files in a tar.
use Archive::Tar qw();
my $tar_file = 'some_tar_file.tar.gz';
my $tar = Archive::Tar->new($tar_file);
for my $ft ( $tar->get_files ){
    # The variable $ft is an Archive::Tar::File object.
    Print_file_info(
        $ft->name,
        $ft->is_file ? 'file' : 'other',
        $ft->size,
        $ft->mtime,
    );
}

# Print some basic information about files in a directory tree.
use File::Find;
my $dir_name = 'some_directory';
my @files;
find(sub {push @files, $File::Find::name}, $dir_name);
Print_file_info(
    $_,
    -f $_ ? 'file' : 'other',
    -s,
    (stat)[9],
) for @files;
于 2009-08-13T15:21:47.650 に答える
2

アーカイブにあるすべてのファイルがフォルダーにも存在するかどうかを確認する例を次に示します。

# $1 is the file to test
# $2 is the base folder
for file in $( tar --list -f $1 | perl -pe'chomp;$_=qq["'$2'$_" ]' )
do
  # work around bash deficiency
  if [[ -e "$( perl -eprint$file )" ]]
    then
      echo "   $file"
    else
      echo "no $file"
  fi
done

これは私がこれをテストした方法です:

を削除/名前を変更configしてから、次を実行しました。

bash test ダウンロード/update-dnsomatic-0.1.2.tar.gz ダウンロード/

次の出力が得られました。

   「ダウンロード/update-dnsomatic-0.1.2/」
「ダウンロード/update-dnsomatic-0.1.2/config」なし
   「ダウンロード/update-dnsomatic-0.1.2/update-dnsomatic」
   「ダウンロード/update-dnsomatic-0.1.2/README」
   「ダウンロード/update-dnsomatic-0.1.2/install.sh」

私は bash / shell プログラミングが初めてなので、おそらくこれを行うためのより良い方法があります。

于 2009-08-13T16:19:45.023 に答える
2

Perl は、これに関してはやり過ぎです。シェルスクリプトで十分でしょう。ただし、実行する必要がある手順は次のとおりです。

  • tar を一時フォルダーのどこかに展開します。
  • diff -uR2 つのフォルダーを開き、出力をどこかにリダイレクトします (または、必要に応じてパイプしlessます) 。
  • 一時フォルダーをクリーンアップします。

これで完了です。5 ~ 6 行を超えないようにしてください。迅速でテストされていないもの:

#!/bin/sh
mkdir $TEMP/$$
tar -xz -f ../backups/backup.tgz $TEMP/$$
diff -uR $TEMP/$$ ./ | less
rm -rf $TEMP/$$
于 2009-08-13T13:23:56.580 に答える
1

これは、優れた Perl プログラムを作成するための良い出発点になるかもしれません。しかし、それは質問が求めたことを行います。

一緒にハッキングされたばかりで、Perl のベスト プラクティスのほとんどを無視しています。

perl test.pl フル \
     ダウンロード/update-dnsomatic-0.1.2.tar.gz \
     ダウンロード/ \
     更新-dnsomatic-0.1.2
#! /usr/bin/env perl
use strict;
use 5.010;
use warnings;
use autodie;

use Archive::Tar;
use File::Spec::Functions qw'catfile catdir';

my($action,$file,$directory,$special_dir) = @ARGV;

if( @ARGV == 1 ){
  $file = *STDOUT{IO};
}
if( @ARGV == 3 ){
  $special_dir = '';
}

sub has_file(_);
sub same_size($$);
sub find_missing(\%$);

given( lc $action ){

  # only compare names
  when( @{[qw'simple name names']} ){
    my @list = Archive::Tar->list_archive($file);

    say qq'missing file: "$_"' for grep{ ! has_file } @list;
  }

  # compare names, sizes, contents
  when( @{[qw'full aggressive']} ){
    my $next = Archive::Tar->iter($file);
    my( %visited );

    while( my $file = $next->() ){
      next unless $file->is_file;
      my $name = $file->name;
      $visited{$name} = 1;

      unless( has_file($name) ){
        say qq'missing file: "$name"' ;
        next;
      }

      unless( same_size( $name, $file->size ) ){
        say qq'different size: "$name"';
        next;
      }

      next unless $file->size;

      unless( same_checksum( $name, $file->get_content ) ){
        say qq'different checksums: "$name"';
        next;
      }
    }

    say qq'file not in archive: "$_"' for find_missing %visited, $special_dir;
  }

}

sub has_file(_){
  my($file) = @_;
  if( -e catfile $directory, $file ){
    return 1;
  }
  return;
}

sub same_size($$){
  my($file,$size) = @_;
  if( -s catfile($directory,$file) == $size ){
    return $size || '0 but true';
  }
  return; # empty list/undefined
}

sub same_checksum{
  my($file,$contents) = @_;
  require Digest::SHA1;

  my($outside,$inside);

  my $sha1 = Digest::SHA1->new;
  {
    open my $io, '<', catfile $directory, $file;
    $sha1->addfile($io);
    close $io;
    $outside = $sha1->digest;
  }

  $sha1->add($contents);
  $inside = $sha1->digest;


  return 1 if $inside eq $outside;
  return;
}

sub find_missing(\%$){
  my($found,$current_dir) = @_;

  my(@dirs,@files);

  {
    my $open_dir = catdir($directory,$current_dir);
    opendir my($h), $open_dir;

    while( my $elem = readdir $h ){
      next if $elem =~ /^[.]{1,2}[\\\/]?$/;

      my $path = catfile $current_dir, $elem;
      my $open_path = catfile $open_dir, $elem;

      given($open_path){
        when( -d ){
          push @dirs, $path;
        }
        when( -f ){
          push @files, $path, unless $found->{$path};
        }
        default{
          die qq'not a file or a directory: "$path"';
        }
      }
    }
  }

  for my $path ( @dirs ){
    push @files, find_missing %$found, $path;
  }

  return @files;
}

に名前を変更configconfig.rm、 に余分な文字を追加し、で文字をREADME変更しinstall.sh、ファイルを追加した後.test。これが出力されたものです:

不足しているファイル:「update-dnsomatic-0.1.2/config」
別のサイズ: 「update-dnsomatic-0.1.2/README」
異なるチェックサム: 「update-dnsomatic-0.1.2/install.sh」
アーカイブにないファイル: "update-dnsomatic-0.1.2/config.rm"
アーカイブにないファイル: "update-dnsomatic-0.1.2/.test"
于 2009-08-13T21:14:56.817 に答える