do while循环中出现问题

时间:2013-03-16 10:33:48

标签: perl

这是脚本

#!/usr/bin/perl
use strict;
use  warnings;
my($dayago, $prefix, $today_timestamp, $f,
   $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst,
   $daysago, $now, $old, @oldbackup);

opendir(DIR, "/home/ftpusr/backup/") || die("Error cannot open directory");

$now    = time();
$dayago = 3;

#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now-$dayago*60*60*24);
#$today_timestamp=sprintf("%4d%02d%02d",$year+1900,$mon+1,$mday);
#$old_timestamp=

$prefix = ".CATN0000.";

do {
    ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst)
      = localtime($now - $dayago * 60 * 60 * 24);
    $today_timestamp = sprintf("%4d%02d%02d", $year + 1900, $mon + 1, $mday);
    while ($f = readdir(DIR)){
        if ( $f =~ /$prefix$today_timestamp/ ) {
            print "$f\n";
        }
    }
    $dayago -= 1;
    print "$dayago\n";
    print "$today_timestamp\n";
} until ($dayago == 0);
closedir(DIR);

以下是目录

中的文件
-rw-r----- 1 db2inst1 db2grp1  184569856 2013-03-13 10:24 GSRTC.0.db2inst1.NODE0000.CATN0000.20130313102253.001
-rwxr-xr-x 1 db2inst1 db2grp1        259 2013-03-13 13:00 space_check.sh
-rw-r----- 1 db2inst1 db2grp1 1071665152 2013-03-14 10:06 AWDRT.0.db2inst1.NODE0000.CATN0000.20130314095856.001
-rw-r----- 1 db2inst1 db2grp1  184569856 2013-03-14 10:20 GSRTC.0.db2inst1.NODE0000.CATN0000.20130314101854.001
-rw-r--r-- 1 db2inst1 db2grp1          0 2013-03-14 13:49 bkp.sh
-rwxrwxrwx 1 db2inst1 db2grp1       1070 2013-03-14 20:12 awdrt_tabspc_report.sh
-rw-r----- 1 db2inst1 db2grp1 1085296640 2013-03-15 10:11 AWDRT.0.db2inst1.NODE0000.CATN0000.20130315100434.001
-rw-r----- 1 db2inst1 db2grp1  184569856 2013-03-15 10:30 GSRTC.0.db2inst1.NODE0000.CATN0000.20130315102900.001
-rw-r----- 1 db2inst1 db2grp1 1075859456 2013-03-16 12:16 AWDRT.0.db2inst1.NODE0000.CATN0000.20130316121043.001

当我运行脚本时,输出为:

GSRTC.0.db2inst1.NODE0000.CATN0000.20130313102253.001
2
20130313
1
20130314
0
20130315

相反,我想要这些文件:

-rw-r----- 1 db2inst1 db2grp1 1071665152 2013-03-14 10:06 AWDRT.0.db2inst1.NODE0000.CATN0000.20130314095856.001
-rw-r----- 1 db2inst1 db2grp1  184569856 2013-03-14 10:20 GSRTC.0.db2inst1.NODE0000.CATN0000.20130314101854.001
-rw-r----- 1 db2inst1 db2grp1 1085296640 2013-03-15 10:11 AWDRT.0.db2inst1.NODE0000.CATN0000.20130315100434.001
-rw-r----- 1 db2inst1 db2grp1  184569856 2013-03-15 10:30 GSRTC.0.db2inst1.NODE0000.CATN0000.20130315102900.001

我想要的是它应该保留最后一个文件并删除旧备份。 感谢帮助。

3 个答案:

答案 0 :(得分:1)

我无法弄清楚你要做的是什么,但它与名称中嵌入的日期排序(并可能删除?但你没有删除任何东西)文件有关。让我首先指出模块Time::Piece,它允许您从localtime获取信息,除非存储在方便的对象中。您还可以使用strptime class method从格式化的时间创建它们。

在下面的脚本中,我创建了一个数组引用数组,每个引用一个匹配模式的文件。 arrayref的第一个元素是文件名,第二个是从名称中日期字符串的前8位创建的Time::Piece对象。我还创建了一个代表现在的对象。

#!/usr/bin/env perl

use strict;
use warnings;

use Time::Piece;

my $now = localtime();

my $prefix = "CATN0000";
opendir(my $dir, "/home/ftpusr/backup/") || die("Error cannot open directory: $!");

my @files;
while ( my $file = readdir $dir ) {
  $file =~ /\.$prefix\.(\d{8})\d*\.\d{3}/ or next;
  push @files, [ $file, Time::Piece->strptime( $1, '%Y%m%d') ];
}

从这个起点开始,您可以通过比较Time::Piece对象进行排序,将它们与$now对象进行比较,然后根据需要对文件执行任何操作。

答案 1 :(得分:1)

  1. 如果您不理解您的代码,请重新格式化并重构它,直到它尽可能清晰。例如。你可以把时间戳生成代码放在一个单独的子程序中,因为细节只会减损你循环的意图。
  2. 不要预先声明您的变量。这是不合时宜的,使得虫虫难以捕捉,并且是伪装的全局变量。而是在您使用它们的最里面的范围内声明(并立即初始化)变量。
  3. 不要将裸字用作文件或目录句柄。
  4. 现在就实际问题:

    1. 列表上下文中使用的readdir函数将返回该目录中的所有项目。在标量上下文中使用,它返回下一个条目,如果没有其他项目可用,则返回undef。这使它成为一个迭代器。要重置迭代器,您必须重新打开目录。将所有项目读入数组可能会更好,然后选择与特定模式匹配的项目。
    2. 在正则表达式中,句点.是一个元字符,默认情况下匹配任何非换行符。要匹配文字点,您必须将其转义,或将其括在\Q...\E引号中。
    3. 以下是一些可能对您有所帮助的代码:

      计算给定$days_ago的时间戳的子<:h3>
      { # begin a enclosing scope for private variable
          my $now = time;
          my $secs_per_day = 24 * 60 * 60;
      
          sub timestamp {
            my ($ago) = @_;
            # we can use `undef` for vars we don't use
            my (undef, undef, undef, $mday, $mon, $year)
                = localtime( $now - $ago * $secs_per_year);
            return sprintf '%04d%02d%02d', $year + 1900, $mon + 1, $mday;
          }
      }
      

      读取目录中的所有文件:

      my $directory = '/foo/bar';
      my @files = do {
        opendir my $dir, $directory or die "Can't open $directory: $!";
        readdir $dir;
      };
      

      这使用do块。一旦文字超出范围,词汇文件或目录就会自动关闭。变量$!包含失败的原因

      选择所有匹配的文件:

      sub matching_files {
          my ($days_ago, $files) = @_;
          my $timestamp = timestamp($days_ago)
          return grep /\Q .CATN0000. $timestamp \E/x, @$files;
      }
      

      这需要几天前,以及对我们的文件数组的引用。正则表达式上的/x修饰符允许我们包含不匹配的空格以便更好地格式化。 sub可以像my @interesting = matching_files(7, \@files)一样调用(参见参考运算符\)。

      最多两天前获取并打印所有文件

      for my $days_ago (reverse 0 .. 2) {
         my @interesting = matching_files($days_ago, \@files);
         print "Days ago: $days_ago\n";
         print "$_\n" foreach @interesting;
      }
      

      范围运算符..创建序列0, 1, 2,我们将其反转。像for这样的循环结构可以显示为尾随语句修饰符。内部foreach会将每个项目放入$_

答案 2 :(得分:0)

哟这个人为我工作..........

#!/usr/bin/perl
use strict;
use warnings;


my($dayago,$prefix,$today_timestamp,$f,$sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst,$daysago,$now,$old,@oldbackup);
#opendir(DIR, "/home/ftpusr/backup/") || die("Error cannot open directory");
$now=time();
$dayago=3;
#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now-$dayago*60*60*24);
#$today_timestamp=sprintf("%4d%02d%02d",$year+1900,$mon+1,$mday);
#$old_timestamp=
$prefix = ".CATN0000.";
do {
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now-$dayago*60*60*24);
opendir(DIR, "/home/ftpusr/backup/") || die("Error cannot open directory");
$today_timestamp=sprintf("%4d%02d%02d",$year+1900,$mon+1,$mday);
while ($f = readdir(DIR)){
  if ( $f =~ /$prefix$today_timestamp/ ) {
        print "$f\n";
        }
}
$dayago -= 1;
print "$dayago\n";
print "$today_timestamp\n";
}until ($dayago == 0);
closedir(DIR);

任何更好的解决方案??????????