2012-01-03 113 views
1

我写这篇文章的备份脚本:故障用Perl和焦油

#!/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备份工作正常。提前致谢。

+0

您可以打印正在执行的命令,就在system()add - print“执行tar -cJf $ excludedes $ tmpbdir/$ dir.xz $ dir \ n”之前;并显示打印什么? – dimir 2012-01-03 09:09:26

+0

'执行tar -cJf --exclude/home/webserver/ubuntubarsport/www/minecraft/* /mnt/backup/tmp/backup_2012-01-03-1325581860//home.xz/home'并执行tar -cJf/mnt/backup/tmp/backup_2012-01-03-1325581860 // etc.xz/etc' for/etc,这是可行的。 我真的不知道为什么在$ tmpbdir中有一个斜线,因为我将其定义为'$ tmpbdir =“$ tmpdir/backup_ $ now”' – turlando 2012-01-03 09:14:08

+0

但是/ etc和/ home在路径中有一个起始斜线: D发现错误。我希望。 – turlando 2012-01-03 09:22:04

回答

1

您错过了您尝试创建备份tarball的目录。添加

system("mkdir -p $tmpbdir"); 

到backup()的开头。

编辑

而且备份压缩包应该是-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的--exclude预计模式。

+0

没有任何更改:\ – turlando 2012-01-03 16:07:39

+0

我编辑了答案。 – dimir 2012-01-03 16:35:07

+0

我修改了脚本;现在它不返回任何错误,但是我排除了所有文件:\ – turlando 2012-01-03 17:19:19

1

使用以下模块中的Perl脚本,而不是使用system通话:

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

最后,您可能会发现这更快,更灵活。另外,它的处理问题(即使用Perl模块来代替炮击了操作系统的命令。

而且,因为你现在正在写纯Perl的一切,你没有的正确方式问题如何您的system命令与命令行进行交互或在计算机上的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_listfind中的子程序可用于过滤掉任何你不想要的东西。而且,您也可以使用对子例程的引用。以下内容与上述相同。

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。
  • 使用$object->add_files在您的tarball中添加所需的文件。
  • 完成时,使用$object->write写压缩包到磁盘上,靠近$object

试一试,这是不是太困难,你会提高你的Perl编程技能。