Perl 和 tar 的问题

发布于 2024-12-24 02:12:14 字数 2775 浏览 0 评论 0原文

我正在编写这个备份脚本:

#!/usr/bin/perl
use strict;
use POSIX qw(strftime);
use DBI;

my $destdir       = "/mnt/backup";
my $tmpdir        = "/mnt/backup/tmp";
my $mysqlpassword = "";

my %backup = (
    '/home' => [
        'path/to/exclude/from/backup/*',
    ],
    '/etc',
);

my $now = strftime("%Y-%m-%d-%s", localtime);
my $tmpbdir = "$tmpdir/backup_$now";

sub printlog
{
    print "[", strftime("%D %T", localtime), "] $_[0]\n";
}

sub backup
{
    foreach my $dir (keys %backup) {
        printlog "Backing up $dir...";
        my $excludes = "";
        if ($#{$backup{$dir}}+1 > 0) {
            for my $i (0 .. $#{$backup{$dir}}) {
                $excludes = "--exclude $dir/$backup{$dir}[$i] ";
            }
            $excludes =~ s/\s$//;
        }
        system("tar -cJf $excludes $tmpbdir/$dir.xz $dir");
        printlog "$dir backup complete.";
    }
}

sub backup_mysql
{
    printlog "Backing up MySQL...";
    mkdir("$tmpbdir/mysql");
    my $dbh = DBI->connect('dbi:mysql:information_schema', 'root', $mysqlpassword, {'RaiseError' => 1});
    if ($dbh) {
        my $sth = $dbh->prepare('SELECT SCHEMA_NAME AS `Database` FROM INFORMATION_SCHEMA.SCHEMATA'); $sth->execute;
        while (my @databases = $sth->fetchrow_array) {
            system("mysqldump --opt --single-transaction --user=root --password=$mysqlpassword $databases[0] > $tmpbdir/mysql/$databases[0].sql");
        }
        system("tar -cjf $tmpbdir/mysql.xz $tmpbdir/mysql");
        system("rm -rf $tmpbdir/mysql");
        printlog "MySQL backup complete.";
    } else {
        print "Unable to connect to MySQL server.\n$DBI::errstr\n";
    }
}

sub archive
{
    printlog "Archiving...";
    system("tar -cf $destdir/backup_$now.tar $tmpbdir/*");
    system("rm -rf $tmpbdir");
    printlog "Backup complete in $destdir/backup_$now.tar";
}

if ($> != 0) {
    die "You must run this script as root.\n";
}

printlog "Backup starts.";
mkdir($tmpbdir);

&backup;
&backup_mysql;
&archive;

但是当我运行该脚本时,/home 备份失败。这是脚本的输出。

[...]
[01/03/12 03:00:03] Backing up /home...
tar: Removing leading `/' from member names
tar: /mnt/backup/tmp/backup_2012-01-03-1325556001//home.xz: Cannot stat: No such file or directory
tar: /home/minecraft/world/region/r.-1.1.mcr: file changed as we read it
tar: /home/minecraft/world: file changed as we read it
tar: /home/webserver/ubuntubarsport/log/access_log: file changed as we read it
tar: Removing leading `/' from hard link targets
tar: Exiting with failure status due to previous errors
[...]

我不知道 tar: /mnt/backup/tmp/backup_2012-01-03-1325556001//home.xz: Cannot stat: No such file or directory 的原因。我做错了什么? /etc 备份工作正常。提前致谢。

I'm writing this backup script:

#!/usr/bin/perl
use strict;
use POSIX qw(strftime);
use DBI;

my $destdir       = "/mnt/backup";
my $tmpdir        = "/mnt/backup/tmp";
my $mysqlpassword = "";

my %backup = (
    '/home' => [
        'path/to/exclude/from/backup/*',
    ],
    '/etc',
);

my $now = strftime("%Y-%m-%d-%s", localtime);
my $tmpbdir = "$tmpdir/backup_$now";

sub printlog
{
    print "[", strftime("%D %T", localtime), "] $_[0]\n";
}

sub backup
{
    foreach my $dir (keys %backup) {
        printlog "Backing up $dir...";
        my $excludes = "";
        if ($#{$backup{$dir}}+1 > 0) {
            for my $i (0 .. $#{$backup{$dir}}) {
                $excludes = "--exclude $dir/$backup{$dir}[$i] ";
            }
            $excludes =~ s/\s$//;
        }
        system("tar -cJf $excludes $tmpbdir/$dir.xz $dir");
        printlog "$dir backup complete.";
    }
}

sub backup_mysql
{
    printlog "Backing up MySQL...";
    mkdir("$tmpbdir/mysql");
    my $dbh = DBI->connect('dbi:mysql:information_schema', 'root', $mysqlpassword, {'RaiseError' => 1});
    if ($dbh) {
        my $sth = $dbh->prepare('SELECT SCHEMA_NAME AS `Database` FROM INFORMATION_SCHEMA.SCHEMATA'); $sth->execute;
        while (my @databases = $sth->fetchrow_array) {
            system("mysqldump --opt --single-transaction --user=root --password=$mysqlpassword $databases[0] > $tmpbdir/mysql/$databases[0].sql");
        }
        system("tar -cjf $tmpbdir/mysql.xz $tmpbdir/mysql");
        system("rm -rf $tmpbdir/mysql");
        printlog "MySQL backup complete.";
    } else {
        print "Unable to connect to MySQL server.\n$DBI::errstr\n";
    }
}

sub archive
{
    printlog "Archiving...";
    system("tar -cf $destdir/backup_$now.tar $tmpbdir/*");
    system("rm -rf $tmpbdir");
    printlog "Backup complete in $destdir/backup_$now.tar";
}

if (
gt; != 0) {
    die "You must run this script as root.\n";
}

printlog "Backup starts.";
mkdir($tmpbdir);

&backup;
&backup_mysql;
&archive;

But when I run the script, the /home backup fails. This is the output of the script.

[...]
[01/03/12 03:00:03] Backing up /home...
tar: Removing leading `/' from member names
tar: /mnt/backup/tmp/backup_2012-01-03-1325556001//home.xz: Cannot stat: No such file or directory
tar: /home/minecraft/world/region/r.-1.1.mcr: file changed as we read it
tar: /home/minecraft/world: file changed as we read it
tar: /home/webserver/ubuntubarsport/log/access_log: file changed as we read it
tar: Removing leading `/' from hard link targets
tar: Exiting with failure status due to previous errors
[...]

I don't know the reason of tar: /mnt/backup/tmp/backup_2012-01-03-1325556001//home.xz: Cannot stat: No such file or directory. What am I doing wrong? The /etc backup works fine. Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

洋洋洒洒 2024-12-31 02:12:14

您缺少尝试在其中创建备份 tarball 的目录。添加

system("mkdir -p $tmpbdir");

到 backup() 的开头。

编辑

备份 tarball 也应该在 -f 之后的命令行上,因此

system("tar -cJf $excludes $tmpbdir/$dir.xz $dir");

您应该使用

system("tar $excludes -cJf $tmpbdir/$dir.xz $dir");

编辑

从排除中删除前导斜杠:

'home/webserver/ubuntubarsport/www/minecraft/*'

如果您不这样做不需要该目录本身也尾随斜杠和星号:

'home/webserver/ubuntubarsport/www/minecraft'

请记住, tar< /a> 的--排除预期 图案。

You are missing a directory in which you are trying to create a backup tarball. Add

system("mkdir -p $tmpbdir");

to the beginning of backup().

EDIT:

Also the backup tarball should be on the command line right after -f, so instead of

system("tar -cJf $excludes $tmpbdir/$dir.xz $dir");

you should have

system("tar $excludes -cJf $tmpbdir/$dir.xz $dir");

EDIT:

Remove the leading slash from excludes:

'home/webserver/ubuntubarsport/www/minecraft/*'

And if you don't need that directory itself also trailing slash and asterisk:

'home/webserver/ubuntubarsport/www/minecraft'

Keep in mind, that tar's --exclude expects pattern.

人疚 2024-12-31 02:12:14

在 Perl 脚本中使用以下模块,而不是使用 system 调用:

这消除了系统不兼容的可能问题,并且您可以更好地控制备份内容和备份位置。是的,这需要你付出更多的努力。如果您不熟悉这两个模块,则必须学习它们,但这两个模块自 Perl 5.10 起就已包含在 Perl 中。而且,如果您使用旧版本的 Perl,则可以从 CPAN 安装它们。

最后,您可能会发现这更快、更灵活。另外,这是处理问题的正确方法(即,使用 Perl 模块而不是使用操作系统命令。

而且,由于您现在用纯 Perl 编写所有内容,因此您不必您的系统命令如何与命令行交互或者计算机上的tar版本

非常简单(注意:代码未验证):

use File::Find;

my @dirList = qw(list of directories to go through);
my @file_list;

find ({
   push @file_list, $File::Find::name if -f; #Backup files only
}, @dirList);

这应该放置您的文件到 @file_list 中。find 中的子例程可用于过滤掉您不需要的任何内容,并且您也可以使用对子例程的引用,如下所示。与上面相同,

find (\&wanted, @dir_list);

sub wanted {
   if (-f) {   #Use the `if` to see whether you want to backup a file.
       push @file_list, $File::Find::name;
   }
}

我对 Archive::Tar 有点犹豫,但如果我记得的话,这是一个几个步骤的过程:

  • 使用 my $object = Archive::Tar->new 创建对象
  • 使用$object->create_archive 创建新的tarball
  • 。 ->add_files 在 tarball 中添加所需的文件
  • 完成后,使用 $object->write 将 tarball 写入磁盘并关闭 $object< /code>

尝试一下,它并不是太难,而且您将提高 Perl 编程技能。

Use the following modules in your Perl script instead of using your system call:

This removes the possible issues of system incompatibility, and you'll have more control over what you're backing up and where. Yes, it'll take a wee bit more elbow grease on your part. You'll have to learn these two modules, if you're not familiar with them, but both of these modules have been included in Perl since Perl 5.10. And, if you're using an older version of Perl, you can install them from CPAN.

In the end, you'll probably find this faster and more flexible. Plus, it's the correct way to handle the issue (i.e., use Perl modules instead of shelling out to operating system commands.

And, since you're now writing everything in pure Perl, you don't have the issue of how your system command interacts with the command line or what version of tar is on the computer.

File::Find is pretty simple (NOTE: Code not verified):

use File::Find;

my @dirList = qw(list of directories to go through);
my @file_list;

find ({
   push @file_list, $File::Find::name if -f; #Backup files only
}, @dirList);

This should put your files into @file_list. The subroutine in find can be used to filter out anything you don't want. And, you can use a reference to a subroutine too. The following is the same as above.

find (\&wanted, @dir_list);

sub wanted {
   if (-f) {   #Use the `if` to see whether you want to backup a file.
       push @file_list, $File::Find::name;
   }
}

I'm a bit more wobbly on Archive::Tar, but if I remember, it's a several step process:

  • Use my $object = Archive::Tar->new to create an object.
  • Use $object->create_archive to create a new tarball.
  • Use $object->add_files to add the files you want in your tarball.
  • When you finish, use $object->write to write the tarball to disk and close $object

Give it a try, it isn't too difficult, and you'll improve your Perl programming skills.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文