2012-01-03 91 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編程技能。