Perl do while循环中出现问题

Perl do while循环中出现问题,perl,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 canno

这是剧本

#!/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
我想要的是它应该保留最后一个文件并删除旧的备份。
非常感谢您的帮助。

这一个对我有用

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

有更好的解决方案吗?????

我不太清楚您想做什么,但它与在名称中嵌入的日期之前对文件进行排序(并可能删除?尽管您没有删除任何内容)有关。首先让我指出一个模块,它允许您从
localtime
获取信息,但存储在方便的对象中的信息除外。此外,您还可以使用从格式化时间创建它们

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

#!/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
对象进行比较,然后根据需要对文件执行任何操作

  • 如果您不理解您的代码,请重新格式化并重构它,直到它尽可能清晰。例如,您可以将时间戳生成代码放在一个单独的子例程中,因为细节只会影响循环的意图
  • 不要预先声明你的变量。这是不礼貌的,使得bug搜索变得困难,并且是伪装的全局变量。相反,在使用变量的最内层范围内声明(并立即初始化)变量
  • 不要使用裸字作为文件或目录句柄
  • 现在谈谈实际问题:

  • 列表上下文中使用的
    readdir
    函数将返回该目录中的所有项目。在标量上下文中使用,它返回下一个条目,如果没有其他可用项,则返回
    undef
    。这使它成为一个迭代器。要重置迭代器,必须重新打开目录。最好将所有项读入一个数组,然后选择与特定模式匹配的项
  • 在正则表达式中,句点
    是元字符,默认情况下与任何非换行符匹配。要匹配文字点,必须将其转义,或将其括在
    \Q..\E
    引号中
  • 以下是一些可能对您有所帮助的代码: 计算
    $days\u之前给定的时间戳的子组件:
    正在读取目录中的所有文件:
    这将使用
    do
    块。词法文件或目录句柄一旦超出范围就会自动关闭。变量
    $包含失败的原因

    选择所有匹配的文件: 这需要几天前的时间,以及对我们的文件数组的引用。正则表达式上的
    /x
    修饰符允许我们包含不匹配的空白,以便更好地格式化。可以像
    my@interest=matching\u files(7,\@files)
    (请参阅参考运算符
    \

    获取和打印两天前的所有文件
    范围操作符
    创建序列
    0,1,2
    ,我们将其反转。类似于
    for
    的循环结构可以显示为尾部语句修饰符。内部的
    foreach
    将把每个项目放入
    $\u

    标题应反映问题的内容。对不起。。。。。。。。。请不要修改,以便更清楚地说明您想要做什么。最后一句话是一个开始,但我仍然不能理解它的头绪。
    { # 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;
    };
    
    sub matching_files {
        my ($days_ago, $files) = @_;
        my $timestamp = timestamp($days_ago)
        return grep /\Q .CATN0000. $timestamp \E/x, @$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;
    }