比较不同文件的两列并打印是否匹配


16

我正在使用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|

我的文件很大,包含大约40万行,因此我想加快执行速度。


我从示例中删除了前导空格,如果需要,请回滚编辑。请记住,空格很重要,只有在实际文件中存在空格的情况下才应使用空格。
terdon

尝试使用的GNU版本grep,它的下/usr/sfw/bin/ggrepstackoverflow.com/questions/15259882/...
SLM

Answers:


21

这是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的前两列保存在内存中。如果您只有几十万行,那应该不成问题,但是如果有的话,您可以执行类似的操作

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

但这会更慢。


但是这不会将全部(前两列)加载file2到内存中吗?
Joseph R.

@terdon:awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0'是较短的版本。
cuonglm 2014年

它不起作用..
2014年

@ user68365:是否file2有重复的行?
cuonglm 2014年

不,它没有任何重复的行
user68365 2014年

1

我认为

grep -Ff file2 file1

是您要寻找的。它应该是有效的,但是我不确定它是否会像您想要的那样准确。如果abc|123(例如)在一行中file1的不同列中找到该行,则也会打印该行。如果您可以保证绝对不会发生这种情况,那么上面的那行应该起作用。


因为abc | 123可能存在于文件中的某个地方,所以grep就不够了。此外,我正在使用solaris 10,我也无法使用该grep选项。
user68365 2014年

2
@ user68365,请澄清您的问题。您需要告诉我们您的操作系统,并指定您只想匹配前两列。
terdon

1

如果您想以类似的方式来考虑SQL中的问题,那么您绝对应该尝试使用名为' q ' 的工具:

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

如果您熟悉SQL查询,则更加清晰易懂。


到目前为止,感谢您提出的最不可靠的解决方案之一。这就是我想要的。但是我在找到这个“ q工具”时
Rolf

非常有用的工具。
ghilesZ '18

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

1
正如我在问题中编辑和提到的那样,grep -f选项在我的系统中
不起作用

Solaris 10在/ usr / sfw / bin中使用了gnu core-utils。使用/ usr / sfw / bin / sed和/ usr / sfw / bin / grep
mr_tron 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.