Perl:从数组中打开文件并逐个读取

3

I have an array in Perl that looks like this:

 my @dynfiles = ('dyn.abc.transcript', 'dyn.def.transcript', 'dyn.ghi.transcript', 'dyn.jkl.transcript');

我想打开这些文件并逐个读取它们。为此,我有一段代码看起来像这样:

foreach my $dynfile (@dynfiles) {
    print "$dynfile\n";
    open my $fh , '<', $dynfile or die "Could not open file\n";
    my %data;
    $data{$dynfile} = do {
        local $/ = undef;
        while (my $line = <$fh>) {
            chomp $line;
            if ($line =~ m/Errors:\s+0/) {
                print "Dyn run status: PASS\n";
            } else { 
                print "Dyn Run status : FAIL\n";
            }
        }
        close $fh;
    }
}

我收到以下错误信息作为输出:
dyn.bxt.transcript
Dyn run status: FAIL
dyn.cnl.transcript
17:25:19 : -E- Could not open dyn.cnl.transcript

所以我的问题是它根本没有读取数组中的文件。此外,这个文件 dyn.bxt.transcript 中有这个字符串 Errors : 0,但我仍然在输出中得到 Dyn run status: FAIL。我在这里做错了什么吗?我使用了简单的模式匹配,不确定问题出在哪里。请帮忙看一下。
提前感谢!

匹配是区分大小写的,或者您可以添加/i标志。另外,请使用适当的缩进格式化您的代码。 - hmatt1
如果在“Errors”和分号之间有空格,则它将无法匹配您的正则表达式。 - hmatt1
没有零填充。我只有这个字符串“Errors : 0”。m/Errors\s*:\s0/i或m/Errors\s:\s*(\d+)/i仍然不起作用:( - chmod
1
我创建了一个聊天室,加入后我会帮你调试:http://chat.stackoverflow.com/rooms/72962/perl-open-files-from-array-and-read-one-by-one - hmatt1
@chiIemagic..我没有足够的积分在聊天室里发言 :( - chmod
显示剩余3条评论
3个回答

2

在查看了您的代码并进行了聊天调试后,我可能会选择类似于以下内容的东西:

sub dynamo_check {

    opendir(my $dh, $log_file) or die "can't opendir $log_file: $!";
    my @dynfiles = grep { /^dynamo.*transcript$/ && -f "$log_file/$_" } readdir($dh);
    close $dh;

    foreach my $dynamofile (@dynfiles) {
        print "Checking file: $dynamofile\n";

        open my $fh, '<', $log_file . $dynamofile or die "$!\n";

        my $passed = 0;

        while(my $line = <$fh>) {
            if ($line =~ m/Errors\s*:\s*0/i) {
                $passed = 1;
                last;
            }
        }
        if ( $passed == 1 ) {
            print "Dynamo run status: PASS\n";
            $data{$dynamofile} = "pass";
        }else {
            print "Dynamo run status: FAIL\n";
            $data{$dynamofile} = "fail";
        }
    }
    print Dumper(\%data);
}

变更摘要:

  • perlvar中引用$!以获得更好的错误信息。
  • 使用grepreaddir查找要读取的文件,而不是硬编码。
  • 打开文件时将目录路径添加到文件名前缀。
  • 移除do块;
  • %data中的值设置为passfail
  • 这里不需要使用chomp
  • 不需要设置local $/ = undef;,我们可以逐行遍历并在找到Errors行时使用last退出while循环。

@chilemagic..这真的很有用,对我很有效!我正在尝试在其他子程序中使用相同的逻辑,就像我们在聊天中讨论的那样,但我遇到了一个问题..请让我知道您何时再次有空进行快速聊天? :) - chmod
嘿@chmod,在聊天室里发布你所拥有的关于这个问题的信息:http://chat.stackoverflow.com/rooms/72962/perl-open-files-from-array-and-read-one-by-one,我今天或明天会看一下! - hmatt1
@chilemagic 最终成功修正了脚本..谢谢! :) - chmod

2

首先,让Perl告诉你为什么无法打开文件:

open my $fh , '<', $dynfile or die "Could not open file $!\n";

我注意到你的错误信息引用了在@dynfiles中不存在的 dyn.bxt.transcriptdyn.cnl.transcript。如果你能构建一个包含样例输入的完整且简洁的脚本,将会很有帮助。
接下来,你取消了输入记录分隔符,之后使用了while,这通常只会返回整个文件的单行。这通常是不好的。
然后,似乎你的模式不匹配字符串Errors : 0,因为其中有一个空格。
        if ($line =~ m/Errors\s*:\s+0/) {

我不确定你在使用 do 时想做什么。它会返回最后一个被评估的表达式,而在你的情况下是 close $fh。但是,那个 %data 哈希只在块的每次迭代结束时存在。再次强调,剔除与解决这个问题无关的内容。


你关于模式匹配的想法是正确的 - 是的,我漏掉了这个字符串中的一个空格:'Errors : 0',而你建议的正则表达式起作用了! - chmod

1

您可以使用一些经过充分测试的模块来减少代码量。例如,使用我最喜欢的Path::Tiny之一,您可以编写如下代码:

use 5.014;
use warnings;
use Path::Tiny;

my @dynfiles = map { "dyn.$_.transcript" } qw(abc def ghi jkl);
say "Dyn run status: ",
    (path($_)->slurp =~ /error\s*:\s*0\b/i)
        ? "PASS"
        : "FAIL"
    for (grep {-f} @dynfiles);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接