如何处理不包含模式的文件?

时间:2017-10-28 00:43:28

标签: regex perl file grep

我的Perl程序需要帮助。我们的想法是从命令行传入一个模式和一个文件列表。如果文件名与模式匹配,则打印文件名。然后,如果文件名不匹配,它应该在文件的文本中查找模式的实例并打印文件名:包含出现的第一行文本

但是,如果用户在开头添加-i选项,则应该发生相反的情况。如果文件名不匹配则打印它。然后在文本中打印任何不包含任何模式实例的文件。

最后一部分是我在努力的地方我不确定如何获取文本中没有模式的文件。例如在我的代码中

#!/usr/bin/perl -w
die("\n Usage: find.pl [-i] <perlRegexPattern> <listOfFiles>\n\n") if(@ARGV<2);

my (@array,$pattern,@filesmatch,@files);
#I can separate files based on name match
($pattern,@array) = ($ARGV[0] eq "-i") ? (@ARGV[1 .. $#ARGV]) : (@ARGV);

foreach(@array){
    ($_ =~ m/.*\/?$pattern/) ? (push @filesmatch,$_) : (push @files, $_);
}
#and I can get files that contain a pattern match in their text
if($ARGV[0] ne "-i"){
    for my $matches(@filesmatch){ #remove path print just file name
        $matches =~s/.*\///;      #/
        print "$matches\n";
    }
    for my $file(@files){
        open(FILE,'<',$file) or die("\nCould not open file $file\n\n");
        while(my $line = <FILE>){
            if($line =~ m/$pattern/){
                $file =~ s/.*\///; #/ remove path print just file name
                print "$file: $line";
                next;
            }
        }
    }
}
#however I'm not sure how to say this file dosen't have any matches so print it
else{
    for my $matches(@files){ #remove path print just file name
        $matches =~ s/.*\///;
        print "$matches\n";
    }
    for my $file(@filesmatch){
        open(FILE,'<',$file) or die("\nCould not open file $file\n\n");;
        while(my $line = <FILE>){...

我不确定是否可以使用类似grep的内容来完成此操作,但我很难使用Perl的grep

1 个答案:

答案 0 :(得分:3)

要根据内容决定是否打印文件,您必须先读取文件。根据您的标准 - 短语不存在 - 您必须检查整个文件。

标准方法是使用单独的变量(&#34;标记&#34;)来记录条件然后返回打印

my $has_match;
while (<$fh>) {
   if (/$pattern/) {
       $has_match = 1;
       last;
   }
}
if (not $has_match) {
    seek $fh, 0, 0;     # rewind to the beginning
    print while <$fh>;
}

首先将文件读入变量,并使用labels(另请参阅perlsyn

,可以简化此操作
FILE: foreach my $file (@filesmatch) {
    open my $fh, '<', $file or die "Can't open $file: $!";
    my @lines = <$fh>;

    for (@lines) {
        next FILE if /$pattern/;
    }   
    print for @lines;
}

请注意,在循环中间跳过迭代并不是最干净的方法,因为必须始终牢记循环的其余部分可能无法运行。

首先阅读每个文件,以便我们不会两次阅读,但如果任何文件可能很大,请不要这样做。

如果有任何命令行处理,最好使用模块; Getopt::Long很不错。

use Getopt::Long;

my ($inverse, $pattern);    
GetOptions('inverse|i' => \$inverse, 'pattern=s' => \$pattern)
    or usage(), exit;    
usage(), exit if not $pattern or not @ARGV;

sub usage { say STDERR "Usage: $0 ... " }

将程序称为progname [-i] --patern PATTERN files。该模块提供了很多,请参阅文档。例如,在这种情况下,您也可以使用-p PATTERN

GetOptions解析命令行时,提交的选项将从@ARGV中删除,其中剩余的是文件名。你有$inverse变量可以很好地做出决定。

请在每个程序的顶部use warnings; -w)和use strict;