解释:

解释:

我正在尝试找到一种有效的方法来使用 bash 脚本进行一些比较。我正在使用 grep 和 awk,但它非常慢,而且我没有很好的方法来分离匹配项。

考虑输入文件1:

311 2222
833 7777
Jam 33333

并输入文件2:

A 833 0 0 0 0 7777 0 0 0 0
B no match - 2222 833 3333
C the cow jumps over the 311 moon 2222
D illicit Jam fox 33333 
E no match - Jam 
F 7777 833

实际上,file1 约为 100 行,file2 约为 10,000 行。

我想将 file1 中的两个字符串与 file2 中的每一行进行比较。如果两个字符串在该行的任意位置都匹配,则打印 file2 中的该行。对于上面的示例,理想情况下输出将与此类似(但格式化为列):

C the cow jumps over the 311 moon 2222
---<separator>---
A 833 0 0 0 0 7777 0 0 0 0
F 7777 833
---<separator>--- 
D illicit Jam fox 33333 

请注意,匹配项通过它们之间的分隔符分组在一起(833 7777 匹配 file2 中的两行)。优选地,所有匹配都是单词匹配。

另请注意:file1 中的每一行将匹配 file2 中的一行或多行,但 file2 中的每一行将匹配 file1 中的 1 行或 0 行。

[更新了 file2 中的“不匹配”行]

谢谢

答案1

这是一个纯 awk 解决方案,适用于模式文件中每行两个模式(以空格分隔),并具有逻辑 AND 运算:

awk 'NR==FNR{patts[$1]=$2;next}{for (i in patts) if (($0 ~ i) && ($0 ~ patts[i])) print}' patterns file

更新
对于单词而不是正则表达式匹配,您可以评估此​​替代方案:

awk 'NR==FNR{patts[$0]="\\<" $1 "\\>.*\\<" $2 "\\>|\\<" $2 "\\>.*\\<" $1 "\\>";next} \
{for (i in patts) if ($0 ~ patts[i]) print}' patterns file1   

它实际上正在将模式转换833 7777
\<833\>.*\<7777\> | \<7777\>.*\<833\>进行单词匹配并模拟这两种模式的逻辑“与”。

该解决方案经过测试,与以下记录不匹配G 77771 2833

更新2号
这将确保单词匹配、逻辑 AND 运算以及使用分隔符字符串打印每个匹配的组。

awk 'NR==FNR{patts[$0]="\\<" $1 "\\>.*\\<" $2 "\\>|\\<" $2 "\\>.*\\<" $1 "\\>";next} \
{for (i in patts) {if ($0 ~ patts[i]) !found[i]?found[i]=$0:found[i]=found[i] ORS $0}} \
END{for (k in found) {print found[k];print "-----"}}' patterns file1

#Output
A 833 0 0 0 0 7777 0 0 0 0
F 7777 833
-----
D illicit Jam fox 33333
-----                  
C the cow jumps over the 311 moon 2222
----- 

在线测试在这里。

PS:由于 awk 处理关联数组的方式,我们不能影响 END 部分中找到的数组的打印。它将以某种方式“随机”。

答案2

如果已知file1的每一行正好有两个字符串:

while read -ra elements; do
   grep "${elements[0]}" file2 | \
     grep "${elements[1]}" && \
     echo "----"
done < file1

答案3

我会这样做,perl因为我认为它看起来更清楚:

#!/usr/#bin/env perl
use strict;
use warnings;
use Data::Dumper;


my ( $pattern_file_name, $process_file_name ) = @ARGV; 

open ( my $patterns_file, '<', $pattern_file_name ) or die $!;
my @matches = map { [split] } <$patterns_file>;
close ( $patterns_file );

print "Using:\n";
print Dumper \@matches;

#my @matches = ( [ '311', '2222' ], [ '833', '7777' ], [ 'Jam', '33333' ] );

#read main file
my @results;
open  ( my $input, '<', $process_file_name ) or die $!; 

#iterate a line at a time. 
while ( my $line = <$input> ) {
 GROUP:
   for my $id ( 0 .. $#matches ) {
      #Check each set of expressions.
      foreach my $expression ( @{ $matches[$id] } ) { 
         #move to the next group if any don't match
         next GROUP unless $line =~ m/$expression/;
      }
      #didn't get skipped, so must have matched all. 
      push( @{ $results[$id] }, $line );
   }
}
print Dumper \@results;

print "\n$_\n" for @results;
close ( $input );

答案4

perl -wMstrict -Mvars='*f2' -l -0777ane '
   if ( ! @ARGV ) {# this is File1 zone: slurped in $_
      while ( /^(\S+)\s+(\S+)$/mg ) {
         my $rx = qr/^(?=.*$1)(?=.*$2)/m; # AND matching of $1/$2
         pos($f2)=0;
         $f2 =~ /\G([^\n]+)/m and print $1 while $f2 =~ /$rx/mg;
         print "--- <Separator> ---" unless /\G\n\z/;
      }
   } else {# This is File2 zone: slurped whole in $f2
      $f2 = $_;
   }
' File2 File1 #<----- order is important here

解释:

我们必须记住,打印的顺序在这里非常重要。 File2 的行按照 File1 中的字符串确定的顺序打印。在 File1 的每一行都与 File1 进行模式匹配后,我们还需要一个单独的行,无论匹配是否成功。文件被吸食,File2 => $f2,并且 File 被视为 $_ in

相关内容