2

我想要做的是让我的程序通过一个目录递归,并且对于目录中的所有这些文件,在每个文件中搜索单词“ERROR”,然后在单独的文件中打印它的实例。我能够做到这一点而无需使其递归,即只需在 cmd 中输入要手动检查的文件。我想知道递归时使用 ARGV 的正确方法是什么。到目前为止,这是我的代码:

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

my $dir = "c:/programs";

find(\&searchForErrors, $dir);

sub searchForErrors()
{
my $seen = 0;

if (-f){
    my $file = $_;
    my @errors = ();

    open FILE, $file;
    my @lines = <FILE>;
    close FILE;

    for my $line (@lines){
        if (/ERROR/ ){
        push(@errors, "ERROR in line $.\n");
        print FILE "ERROR in line $.:$1\n" if (/Error\s+(.+)/);
    }
    open FILE, ">$file";
    print FILE @lines;
    close FILE;
    }
}
}

我需要知道的是如何合并 ARGV,以便程序读取目录中的每个文件,执行搜索,然后将搜索结果输出到文件中。我希望我已经充分解释了我的问题,如果您需要任何澄清,请告诉我什么是令人困惑的。您可以对答案给出的解释越多越好。谢谢!

4

1 回答 1

4

ARGV通常用于迭代从 Perl 外部提供的文件。

 $ find -type f --exec perl script.pl {} +

 # script.pl
 while (<>) {
     print "$ARGV:$.: $1\n" if /Error\s+(.+)/;
 } continue {
     close(ARGV) if eof;  # Reset $.
 }

但这不是必需的。你也可以这样做:

 use File::Find::Rule qw( );

 @ARGV = File::Find::Rule->file->in('.');
 while (<>) {
     print "$ARGV:$.: $1\n" if /Error\s+(.+)/;
 } continue {
     close(ARGV) if eof;  # Reset $.
 }

我更喜欢File::Find::Rule,但你可以坚持使用File::Find,因为如果你将上面的代码片段与下面的代码片段进行比较,这些原因应该很明显:

use File::Find qw( find );

@ARGV = ();
find({ wanted => sub { push @ARGV, $_ if -f }, no_chdir => 1 }, '.');

 while (<>) {
     print "$ARGV:$.: $1\n" if /Error\s+(.+)/;
 } continue {
     close(ARGV) if eof;  # Reset $.
 }

PS - 您正在用其自身的精确副本替换每个文件,并且您正在填充一个您从未使用过的数组。我从我的版本中省略了该代码。

于 2012-06-11T16:39:47.280 回答