كيف يمكنني مقارنة قائمة الملفات من أرشيف القطران والدليل؟

StackOverflow https://stackoverflow.com/questions/1271879

  •  13-09-2019
  •  | 
  •  

سؤال

ما زلت أتعلم بيرل. يمكن لأي شخص أن يقترح لي رمز PERL مقارنة الملفات من .tar.gz ومسار الدليل.

دعنا نقول أن لدي 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 Test.PL Full  Downloads / Update-Dnsomatic-0.1.2.tar.gz  Downloads /  Update-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;
}

بعد إعادة تسميق config ل config.rm, ، مضيفا شار إضافي README, ، تغيير شار في install.sh, وإضافة ملف .test. وبعد هذا هو ما خرج عنه:

ملف مفقود: "Update-Dnsomatic-0.1.2 / Config" الحجم المختلفة: "Update-Dnsomatic-0.1.2 / Readme" المجموع الاختباري المختلفة: "Update-Dnsomatic-0.1.2 / Install.Sh" لا في الأرشيف: " تحديث-dnsomatic-0.1.2 / config.rm "ملف لا في الأرشيف:" تحديث - Dnsomatic-0.1.2 / .test "

نصائح أخرى

ال Archive::Tar و File::Find الوحدات ستكون مفيدة. يظهر مثال أساسي أدناه. يطبع فقط معلومات حول الملفات الموجودة في القطران والملفات الموجودة في شجرة الدليل.

لم يكن واضحا من سؤالك كيف تريد مقارنة الملفات. إذا كنت بحاجة إلى مقارنة المحتوى الفعلي، get_content() طريقة في Archive::Tar::File من المحتمل أن تكون هناك حاجة. إذا كانت مقارنة أبسط كافية (على سبيل المثال، الاسم والحجم، و MT MENT)، فلن تحتاج إلى أكثر من الأساليب المستخدمة في المثال أدناه.

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

بيرل هو نوع من المبالغة لهذا، حقا. سينصي شل سيبذل جيدا. الخطوات التي تحتاجها لتأخذها على الرغم من:

  • استخراج القطران إلى مجلد مؤقت في مكان ما.
  • diff -uR المجلدين وإعادة توجيه الإخراج في مكان ما (أو ربما الأنابيب إلى less حسب الاقتضاء)
  • تنظيف المجلد المؤقت.

إنتهيت. لا ينبغي أن يكون أكثر من 5-6 خطوط. شيء سريع ومختبر:

#!/bin/sh
mkdir $TEMP/$$
tar -xz -f ../backups/backup.tgz $TEMP/$$
diff -uR $TEMP/$$ ./ | less
rm -rf $TEMP/$$

هيريس مثال يتحقق لمعرفة ما إذا كان كل ملف موجود في أرشيف، موجود أيضا في مجلد.

# $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, ، ثم ركض ما يلي:

باش اختبار التنزيلات / التحديث-Dnsomatic-0.1.2.tar.gz التنزيلات /

الذي أعطى انتاج:

 "التنزيلات / تحديث - DNSOMATIC-0.1.2 /" لا "التنزيلات / تحديث-DNSOMATIC-0.1.2 / تكوين" "التنزيلات / تحديث-DNSOMATIC-0.1.2 / تحديث-DNSOMATIC" التنزيلات / التحديث - DNSOMATIC-0.1. 2 / README "" التنزيلات / التحديث-Dnsomatic-0.1.2 / install.sh "

أنا جديد في برمجة باش / شل، لذلك ربما هناك طريقة أفضل للقيام بذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top