我希望能够在文件列表中搜索模式列表。文件必须包含所有模式,并且模式可以位于文件中的任何位置。
有没有什么方法可以做到这一点?
答案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