我如何搜索文件来查看文件中的任意位置是否包含多个模式?

我如何搜索文件来查看文件中的任意位置是否包含多个模式?

我希望能够在文件列表中搜索模式列表。文件必须包含所有模式,并且模式可以位于文件中的任何位置。

有没有什么方法可以做到这一点?

答案1

我认为使用 grep 无法做到这一点,除非grep对每个模式分别运行(或者可能通过使用环视的某些极其复杂的 Perl 样式正则表达式)。但 awk 可能可以胜任这项任务。假设所有模式都以每行一个的形式出现在名为的文件中patterns,并且输入文件名为input,则可以使用类似以下 awk 程序:

#! /usr/bin/awk -f
# test.awk
FNR == NR {
  # First file, contains patterns
  # save all patterns in an array and keep a count
  patterns[$0] = 1;
  count_patterns++;
  next
}
{
  # Not the first file, so check input for patterns
  for (pat in patterns) {
    # Only test patterns if they haven't been seen before
    # Keep count of matched patterns
    if (! (pat in seen) && $0 ~ pat) {
      seen[pat] = 1;
      count_seen++
    }
  }
}
END {
  # End of all input, check if we saw all patterns
  if (count_patterns == count_seen) {
    print "All patterns matched"
  } else {
    exit 1
  }
}

使用方式如下:

awk -f test.awk patterns input

当然,awk 的正则表达式与 grep 可能有点不同,因此您可能需要调整您的模式。

答案2

可以使用多个grep命令来完成。阅读man grep xargs并执行以下操作

grep -l 'pattern1' -f filelist | \
    xargs grep -l 'pattern2` | \
    xargs grep -l 'pattern3'

第一个函数grep生成包含第一个模式的文件列表。第二个函数 ( xargs grep) 在包含第一个模式的文件中搜索第二个模式。

答案3

是的,grep 可以轻松做到这一点。只需通过 xargs 将文件列表传送给它:

$ <your files list> | xargs -d  '\n' grep -l -f patterns.txt

-d '\n' 告诉 xargs 使用换行符作为分隔符(以防某些文件名中有空格)。

答案4

粗糙、未经过广泛测试、可能不太有效且不请自来(因为您在寻求grep解决方案),但正如 Muru 所说,使用 Perlgrep并不是完成这项工作的正确工具,因此这里有一种使用 Perl 的不同方法(同样,未经过广泛测试,但应该基本没问题)。

它期望以换行符分隔的 PCRE 模式列表作为pattern_file

用法:

./script.pl pattern_file file1 file2 file3 [...]
#!/usr/bin/env perl

use strict;
use warnings;

use feature qw(say);

open(my $pattern_fh, '<', shift(@ARGV)) ||
    die('Error while opening pattern file');

my @patterns;

while (<$pattern_fh>) {
    chomp;
    push(@patterns, $_);
}

my $pattern_count = scalar(@patterns);

while (my $filename = shift(@ARGV)) {
    open(my $file_fh, '<', $filename) ||
        die("Error while opening '${filename}'");

    my $match_count = 0;

    while (<$file_fh>) {
        $match_count == $pattern_count && last;

        chomp();
        foreach my $pattern (@patterns) {
            if (/$pattern/) {
                $match_count++;
            }
        }
    }

    $match_count == $pattern_count &&
        say("File '$filename' matches");
}
% cat pattern_file
[0-9]+
abc
def%
% cat file1
000
no_match
abcdef

% cat file2
000
no_match
abcd
ef

% ./script.pl pattern_file file1 file2
File 'file1' matches

添加了一些调试行:

% ./script.pl pattern_file file1 file2
Matching 000 against [0-9]+
        ^^ it matched
Matching 000 against abc
Matching 000 against def
Matching no_match against [0-9]+
Matching no_match against abc
Matching no_match against def
Matching abcdef against [0-9]+
Matching abcdef against abc
        ^^ it matched
Matching abcdef against def
        ^^ it matched

File 'file1' matches

Matching 000 against [0-9]+
        ^^ it matched
Matching 000 against abc
Matching 000 against def
Matching no_match against [0-9]+
Matching no_match against abc
Matching no_match against def
Matching abcd against [0-9]+
Matching abcd against abc
        ^^ it matched
Matching abcd against def
Matching ef against [0-9]+
Matching ef against abc
Matching ef against def
Matching  against [0-9]+
Matching  against abc
Matching  against def

相关内容