/ / Jak mogę porównać listę plików z archiwum tar i katalogu? - perl, gzip, gunzip

Jak mogę porównać listę plików z archiwum tar i katalogu? - perl, gzip, gunzip

Nadal uczę się Perla. Czy ktoś może zasugerować mi kod Perla, aby porównać pliki z .tar.gz i ścieżkę do katalogu.

Powiedzmy, że mam kopię zapasową tar.gz następującej ścieżki do katalogu, którą zrobiłem kilka dni temu.

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

Teraz chcę porównać pliki i katalogi pod tą ścieżką z plikiem kopii zapasowej tar.gz.

W tym celu zasugeruj kod Perla.

Odpowiedzi:

1 dla odpowiedzi № 1

Może to być dobry punkt wyjścia dla dobrego programu Perla. Robi to, o co prosiło pytanie.

Został po prostu zhakowany i ignoruje większość najlepszych praktyk Perla.

perl test.pl pełna Pliki do pobrania / update-dnsomatic-0.1.2.tar.gz Pliki do pobrania / 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;
}

Po zmianie nazwy config do config.rm, dodając dodatkowy znak do README, zmieniając znak install.shi dodawanie pliku .test. Oto, co wyprowadził:

brakujący plik: „update-dnsomatic-0.1.2 / config ” inny rozmiar: „update-dnsomatic-0.1.2 / README” różne sumy kontrolne: „update-dnsomatic-0.1.2 / install.sh” plik nie znajduje się w archiwum: „update-dnsomatic-0.1.2 / config.rm” plik nie znajduje się w archiwum: „update-dnsomatic-0.1.2 / .test”

5 dla odpowiedzi nr 2

Widzieć Archiwum :: Tar.


5 dla odpowiedzi nr 3

The Archive::Tar i File::Find moduły będą pomocne. Podstawowy przykład pokazano poniżej. Po prostu wyświetla informacje o plikach w tar i plikach w drzewie katalogów.

Z pytania nie wynika jasno, jak chcesz porównywać pliki. Jeśli chcesz porównać rzeczywistą zawartość, get_content() metoda w Archive::Tar::File będzie prawdopodobnie potrzebny. Jeśli odpowiednie porównanie jest prostsze (na przykład nazwa, rozmiar i mtime), nie będziesz potrzebował więcej niż metody użyte w poniższym przykładzie.

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

2 dla odpowiedzi № 4

Perl jest w tym rodzaju przesadą. Skrypt powłoki miałby się dobrze. Kroki, które należy podjąć:

  • Rozpakuj tar do folderu tymczasowego.
  • diff -uR dwa foldery i przekieruj wyjście gdzieś (lub może potok do less odpowiednio)
  • Wyczyść folder tymczasowy.

A ty „skończyłeś. Nie powinno być więcej niż 5-6 linii. Coś szybkiego i niesprawdzonego:

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

2 dla odpowiedzi № 5

Oto przykład, który sprawdza, czy każdy plik znajdujący się w archiwum istnieje również w folderze.

# $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

Tak to przetestowałem:

Usunąłem / zmieniłem nazwę config, a następnie:

test bash Downloads / update-dnsomatic-0.1.2.tar.gz Pobieranie /

Który dał wynik:

„Pobieranie / aktualizacja-dnsomatic-0.1.2 / ” no "Downloads / update-dnsomatic-0.1.2 / config" „Downloads / update-dnsomatic-0.1.2 / update-dnsomatic” „Downloads / update-dnsomatic-0.1.2 / README” „Downloads / update-dnsomatic-0.1.2 / install.sh”

Jestem nowym użytkownikiem programowania bash / shell, więc prawdopodobnie jest to lepszy sposób.