【问题标题】:Adding more features in perl script在 perl 脚本中添加更多功能
【发布时间】:2011-07-21 08:02:55
【问题描述】:

在下面的 perl 脚本中,我用当前日期检查了我的文件夹名称(采用日期格式,如 11-08-31)。如果匹配,我会处理该文件夹。如果今天的日期没有文件夹,它还会检查前一天的文件夹。我已经在这里问过这类问题,但我需要在此处进行一些更改并添加新功能:

  • 如果今天没有找到,脚本会检查上一个日期。但是我需要检查上一个日期是否已经被处理,这样我就不会再次处理它。那么,我需要为它创建一个列表吗?

  • 此脚本仅检查前一个日期。如果我必须检查前两天的情况怎么办?谢谢你的帮助。希望你能理解我的疑惑。

更新:此 perl 脚本在检查当前日期和文件夹名称时自动运行。该文件夹是从其他服务器加载的tar文件夹。

所以,基本上我需要运行脚本,如果它与文件夹名称和当前日期匹配。

问题:有时,我曾经在第二天获取文件夹,而我的 perl 脚本仅检查当前日期。我得到的文件夹的名称是以前的日期(不是当前日期)。所以,我需要手动处理文件夹。我需要在我的 perl 脚本中自动化它


#!/usr/bin/perl
use strict;
use warnings;
use Cwd;
use DateTime;
use File::Copy;

# set to your desired time zone
my $today = DateTime->now( time_zone => "America/New_York" );
my $td = $today->strftime("%y-%m-%d");

# strongly recommended to do date math in the 'floating'/UTC zone
my $yesterday = $today->set_time_zone('floating')->subtract( days => 1);
my $yd = $yesterday->set_time_zone('America/New_York')->strftime("%y-%m-%d");

my $dir = shift or die "Provide path on command line. $!";

if ($dir eq '.') {
    $dir = cwd;
}
elsif ($dir !~ /^\//) {
    $dir = cwd() . "/$dir"; 
}

opendir my $dh, $dir or die $!;
my @dir = sort grep {-d and /$td/ || /$yd/} readdir $dh;
closedir $dh or die $!;
@dir or die "Found no date directories. $!";

my $dday = "$dir/$dir[-1]"; # is today unless today not found, then yesterday
my $fdir = '/some/example/path/';    
my @gzfiles = glob("$dday/*tar.gz");

foreach my $zf (@gzfiles) {  
    next if (($zf =~ /BMP/) || ($zf =~ /LG/) || ($zf =~ /MAP/) || ($zf =~ /STR/)); 
    print "$zf\n";
    copy($zf, $fdir) or die "Unable to copy. $!";
}

【问题讨论】:

  • 你为什么不抓住最新的可用文件夹并处理它?如果我没记错的话,这似乎是你正在尝试的。您还可以检查它的年龄是否在特定的天数范围内。
  • 我想自动完成。我从其他站点获取目录中的文件夹,然后我需要处理它。但有时,文件夹会迟到一天。所以,我还需要检查上一个日期。
  • 请检查问题中的更新部分。
  • 但是您仍然只想处理最新的未处理文件夹吗?要在脚本运行之间跟踪已处理的文件夹,您可以使用纯文本文件或 Storable search.cpan.org/~ams/Storable-2.30/Storable.pm
  • 是的。我需要处理最新的文件夹。但有时,您会在 1 天内获得 2 个文件夹,然后您需要同时处理这两个文件夹。因此,我还需要通过将前一个日期与文件夹名称相匹配来检查这些文件夹。在我的脚本中,我只检查今天的文件夹,如果它不存在,我检查前一个日期。我需要在我的脚本中强制检查两者,看看是否处理了前一个日期文件夹。

标签: perl


【解决方案1】:

好吧,正如mugen kenichi 所建议的那样,另一种方法是使用 Storable。这种方式存储一个哈希,其中包含所有已处理的目录。然后当你运行你的程序时,它可以检查哈希值,看看它们是否已经被处理了。

您需要一个一次性脚本来设置已处理目录的哈希值。

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

# This script to be run 1 time only. Sets up 'processed' directories hash.
# After this script is run, ready to run the daily script.

my $dir = '.'; # or what ever directory the date-directories are stored in

opendir my $dh, $dir or die "Opening failed for directory $dir $!";
my @dir = grep {-d && /^\d\d-\d\d-\d\d$/ && $_ le '11-04-21'} readdir $dh;
closedir $dh or die "Unable to close $dir $!";

my %processed = map {$_ => 1} @dir;

store \%processed, 'processed_dirs.dat';

然后,定期运行一个脚本来查找和处理您的日期目录。

#!/usr/bin/perl
use strict;
use warnings;
use File::Copy;
use Storable;

my $dir = shift or die "Provide path on command line. $!";

my $processed = retrieve('processed_dirs.dat'); # $processed is a hashref

opendir my $dh, $dir or die "Opening failed for directory $dir $!";
my @dir = grep {-d && /^\d\d-\d\d-\d\d$/ && !$processed->{$_} } readdir $dh;
closedir $dh or die "Unable to close $dir $!";
@dir or die "Found no unprocessed date directories";

my $fdir = '/some/example/path';

for my $date (@dir) {
    my $dday = "$dir/$date";
    my @gzfiles = glob("$dday/*tar.gz");

    foreach my $zf (@gzfiles) {  
        next if $zf =~ /BMP/ || $zf =~ /LG/ || $zf =~ /MAP/ || $zf =~ /STR/; 
        print "$zf\n";
        copy($zf, $fdir) or die "Unable to copy $zf to $fdir. $!";
    }
    $processed->{ $date } = 1;
}

store $processed, 'processed_dirs.dat';

【讨论】:

  • 而不是两个脚本,如果我最初在哈希表中硬编码文件夹的名称并稍后添加处理后的文件夹,它会工作吗?我的偏好是只使用一个脚本...您对此有何看法?可行吗?
  • 但我非常感谢您的帮助和时间。你太棒了。
  • 是的,最好将它放在 1 个脚本中。我只需要一个 if 语句,例如:if (! -e 'processed_dirs.dat'),然后对哈希执行我的设置操作并存储它。然后主程序可以继续。
  • 由于我刚刚开始使用perl,所以我知道了一些基本的东西。在您的代码中,我的 @dir = grep {-d && /^\d\d-\d\d-\d\d$/ && !$processed->{$_} } readdir $dh; --> 我不理解“/^\d\d-\d\d-\d\d$/”,如果您在我搞砸整个脚本时添加您告诉我的以下更改,那就太好了。如果你把它做成一个脚本,那就太好了。感谢您的帮助和时间
  • 要了解正则表达式,/^\d\d=\d\d-\d\d$/,请参阅perlrequick 和perlretut。然后,如果您仍有疑问,请询问他们 :-)
【解决方案2】:

如果您希望在应用单次运行后保留这些目录是否已处理的状态,您可以在每个目录中创建一个 .processed 文件,并在处理该目录之前检查该文件是否存在。

如果您只需要在脚本执行期间存储这些目录的状态(已处理或未处理),您可以使用带有目录名称的哈希键:

my %PROCESSED = ();

if ($processing_done) {
  %PROCESSED{$dirname} = 1;
} else {
  %PROCESSED{$dirname} = 0;
}

您可以通过从哈希中读取键值来检查每个目录是否已被处理:

if (%PROCESSED{$dirname} == 0) {
 ... do some processing
} else {
 ... this one is already done
}

【讨论】:

    【解决方案3】:

    此解决方案查找比最近处理的目录日期更新的所有尚未处理的目录。您第一次手动记录它,(在脚本运行之前)。该脚本将从那时起对其进行更新。

    文件可以命名为my $last = 'dir_last.dat'; 我刚刚在命令行输入了一个文件,例如:

    C:\Old_Data\perlp>echo 11-07-14 > dir_last.bat
    
    C:\Old_Data\perlp>type dir_last.bat
    11-07-14
    
    C:\Old_Data\perlp>
    

    假设最新的目录是11-07-14。在运行脚本之前,您必须自己找出这一点。

    #!/usr/bin/perl
    use strict;
    use warnings;
    use File::Copy;
    
    my $dir = shift or die "Provide path on command line. $!";
    
    my $last = 'dir_last.dat';
    
    open my $fh, "<", $last or die "Unable to open $last $!";
    chomp(my $last_proc = <$fh>);
    close $fh or die "Unable to close $last $!";
    
    opendir my $dh, $dir or die "Opening failed for directory $dir $!";
    my @dir = sort grep {-d && /^\d\d-\d\d-\d\d$/ && $_ gt $last_proc} readdir $dh;
    closedir $dh or die "Unable to close $dir $!";
    @dir or die "Found no date directories after last update: $last_proc";
    
    my $fdir = '/some/example/path';
    
    for my $date (@dir) {
        my $dday = "$dir/$date";
        my @gzfiles = glob("$dday/*tar.gz");
    
        foreach my $zf (@gzfiles) {  
            next if $zf =~ /BMP/ || $zf =~ /LG/ || $zf =~ /MAP/ || $zf =~ /STR/; 
            print "$zf\n";
            copy($zf, $fdir) or die "Unable to copy $zf to $fdir. $!";
        }
    }
    
    open  $fh, ">", $last or die "Unable to open $last $!";
    print $fh "$dir[-1]\n"; # record the newest date-directory as processed
    close $fh or die "Unable to close $last $!";
    

    请注意,我不像第一个脚本那样依赖 cwd。那里真的不需要,这里也不需要。 opendir、glob和copy都可以处理点(cwd)目录和相对路径。

    标题包括use strict; 和use warnings; 行。它们的目的是提醒您代码中的错误(大多数 perl 脚本都应该使用它们,除非专家决定排除它们——我不知道是什么原因)。第一行告诉 unix 在哪里可以找到解释器 (perl)。

    【讨论】:

    • 您好,我有一些疑问。我知道我最新处理的文件夹,因为我可以在已处理文件夹列表中看到它。但是我该如何手动放置呢?就像 11-04-21 是最新的文件夹,那么在脚本中,我应该在哪里使用它来代替什么?在您的情况下,11-07-14 是最新处理的文件夹,那么您在脚本中的什么地方使用它?
    • 在上面创建dir_last.dat 文件的位置:echo 11-07-14 &gt; dir_last.bat', just change that to: echo 11-04-21 > dir_last.bat` 在命令行中输入此命令。您只需以这种方式创建一次文件。之后脚本会在代码中保持最新。
    • 令人惊奇的东西......但我想,它仍然有一些问题。假设您在同一日期获得 2 个文件夹。一个文件夹应该在前一天到达,第二个文件夹应该在同一天到达。因此,如果它首先处理第二个文件夹,则 dir_last.dat 将使用新日期进行更新。第一个文件夹永远不会得到处理,因为它的日期比新文件夹的日期要短。
    • 基本上,我得到的文件夹应该来得有点早,但他们没有在指定的时间到达。他们将在下一个日期(当前日期)与另一个文件夹一起到达。所以,我需要检查所有文件夹 i。 e 当前日期和以前的日期文件夹(如果它们没有被处理)。
    猜你喜欢
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 2018-06-01
    • 1970-01-01
    • 2019-10-16
    • 2012-01-04
    • 2010-09-05
    相关资源
    最近更新 更多