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

use*_*365 20 perl shell-script text-processing

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

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

文件 1:

abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|
Run Code Online (Sandbox Code Playgroud)

文件2:

abc|123|
kumar|pki|
cab|234
Run Code Online (Sandbox Code Playgroud)

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

预期输出:

abc|123|BNY|apple|
cab|234|cyx|orange|
Run Code Online (Sandbox Code Playgroud)

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

ter*_*don 23

这就是 awk 的设计目的:

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

解释

  • -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 进行了标记:

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

解释

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

第二行处理 file1,使用相同的正则表达式提取第一两列,如果这些列在%k散列中定义,则打印该行。


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

cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done
Run Code Online (Sandbox Code Playgroud)

但这会更慢。


Jos*_* R. 1

我认为

grep -Ff file2 file1
Run Code Online (Sandbox Code Playgroud)

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

  • @user68365请澄清您问题中的所有内容。您需要告诉我们您的操作系统并指定您只想匹配前两列。 (2认同)