比较不同文件的两列,如果匹配则打印

比较不同文件的两列,如果匹配则打印

我使用的是 Solaris 10,因此涉及 -f 的 grep 选项不起作用。

我有两个用管道分隔的文件:

文件1:

abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|

文件2:

abc|123|
kumar|pki|
cab|234

我想将 file2 的前两列与 file1 进行比较(搜索前两列中 file1 的全部内容),如果它们匹配,则打印 file1 的匹配行。然后搜索文件2的第二行,依此类推。

预期输出:

abc|123|BNY|apple|
cab|234|cyx|orange|

我的文件很大,包含大约 400,000 行,所以我想让执行速度更快。

答案1

这就是 awk 的设计目的:

$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|

解释

  • -F'|':将字段分隔符设置为|
  • NR==FNR:NR 是当前输入行号,FNR 是当前文件的行号。仅当读取第一个文件时,两者才会相等。
  • c[$1$2]++; next:如果这是第一个文件,则将前两个字段保存在c数组中。然后,跳到下一行,以便仅应用于第一个文件。

  • c[$1$2]>0:只有当这是第二个文件时,else 块才会被执行,因此我们检查该文件的字段 1 和 2 是否已经被看到 ( c[$1$2]>0),如果已经被看到,我们打印该行。在 中awk,默认操作是打印该行,因此如果c[$1$2]>0为 true,则将打印该行。


或者,由于您使用 Perl 标记:

perl -e 'open(A, "file2"); while(<A>){/.+?\|[^|]+/ && $k{$&}++};
         while(<>){/.+?\|[^|]+/ && do{print if defined($k{$&})}}' file1

解释

第一行将打开,读取第二行( )file2之前的所有内容,并将其(这是最后一个匹配运算符的结果)保存在哈希中。|.+?\|[^|]+$&%k

第二行处理 file1,使用相同的正则表达式提取前两列并打印该行(如果这些列在哈希中定义)%k


上述两种方法都需要将 file2 的前 2 列保存在内存中。如果你只有几十万行,那应该不是问题,但如果是的话,你可以这样做

cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done

但这会更慢。

答案2

我认为

grep -Ff file2 file1

这就是您正在寻找的。它应该是有效的,但我不确定它会像你想要的那样准确。如果abc|123(例如)在file1不同列的一行中找到,则该行也将被打印。如果你能保证这种情况永远不会发生,那么上面的代码应该可以工作。

答案3

如果你想以 SQL 的方式思考问题,那么你绝对应该尝试一个名为 'q':

$ q -d '|' "select f1.* from file1 f1 join file2 f2 on (f1.c1 = f2.c1 and f1.c2 = f2.c2)"

如果熟悉SQL查询的话会更加清晰易懂。

答案4

$  sed 's/^/\^/' 2.txt > temp.txt ; grep 1.txt -f temp.txt
abc|123|BNY|apple|
cab|234|cyx|orange|

相关内容