在一个文件中查找不在另一个文件中的ID


9

我有两个文件:

abc.txt

abcd
xyz
pqrs

mno.txt

zzon
mkno
abcd
  • 我想检查文件mno.txt中是否有“ abcd” 。
  • 如果“ abcd”在abc.txt首位,则也不必mno.txt首位
  • 两个文件中都有数千个这样的ID。
  • 我还想检查mno.txt中有多少id不在abc.txt中

我怎样才能做到这一点 ?

Answers:


19

如果您的目标是找到常见或罕见的行,comm请在此处输入我的命令。

它比较两个文件,并在三列中显示文件1唯一的行和文件2唯一的行以及两个文件中分别出现的行。您也可以传递它标志来禁止任何此输出。例如,comm -1 file1 file2将取消第一列,即file1特有的内容。comm -12 file1 file2只会显示两个文件中的内容。

有一个很大的警告:输入必须排序。我们可以解决此问题。

这将显示abc中所有不在mno中的内容:

comm -23 <(sort abc.txt) <(sort mno.txt)

您可以通过管道wc -l获取计数。


我的理由comm是,文件排序后,并排比较在计算上非常简单。如果您要处理数百万个这样的问题,那将会有所作为。

这可以通过几个模拟文件来证明。我有一台相当快的计算机,因此为了显示方法之间的差异,我需要一个庞大的样本集。我已经为每个文件使用了1000万个10字符的字符串。

$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > abc.txt
$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > mno.txt

$ time comm -23 <(sort abc.txt) <(sort mno.txt) | wc -l
... 0m10.653s

$ time grep -Fcxv -f abc.txt mno.txt
... 0m23.920s

$ time grep -Fcwv -f abc.txt mno.txt
... 0m40.313s

$ time awk 'NR==FNR{a[$0]++};NR!=FNR && a[$0]' abc.txt  mno.txt | wc -l
... 0m12.161s

排序是我的大部分时间。如果我们假装abc.txt是静态的,则可以对其进行预排序,从而使以后的比较更快:

$ sort abc.txt abc-sorted.txt
$ time comm -23 abc-sorted.txt <(sort mno.txt) | wc -l
... 0m7.426s

您可能会看这些,并认为几秒钟无关紧要,但是我必须强调一点,这些都是在高端计算机上运行的。如果您想在(例如)Raspberry Pi 3上执行此操作,则将需要更慢的周转时间,并且差异会增加到实际上很重要的程度。


7

得到一个清单:

grep -Fwf abc.txt mno.txt

它给你类似的东西:

abcd
abcd
zef

如果您只想获得一个唯一列表,则可以使用它,例如:

grep -Fwf abc.txt mno.txt | sort | uniq

并获得计数:

grep -Fcwv -f abc.txt mno.txt

  • -F 表示:将PATTERN解释为固定字符串列表,而不是正则表达式。
  • -f从FILE获得模式abc.txt
  • 我们寻找mno.txt模式
  • -c 计算比赛次数
  • -w仅查找“整个单词”:匹配的子字符串必须在行的开头,或者在非单词组成字符的前面。同样,它必须在行的末尾,或后跟非单词组成字符。单词组成的字符是字母,数字和下划线。
  • -v 反向搜索

1
如果OP想要一个计数匹配,不应该说是更喜欢grep -cxvFf abc.txt mno.txt
steeldriver '17

刚刚看到它:D ...您一直在这里拯救我:D
Ravexina

仅供参考的fgrepegrep交替理应弃用(赞成grep -Fgrep -E-尽管我不知道有任何人相信,他们将永远消失
steeldriver

使用-x时有必要使用-F吗?
Ravexina

1
这取决于OP希望精确计数的内容-例如,如果mno.txt包含abcdef该计数是否应与匹配或不匹配abcd
钢铁司机

3

我们可以使用awk通过传递两个文件来完成这项工作,首先是模式文件,然后是我们要检查的文件。当我们读取第一个文件时,我们知道这NR==FNR一点,那时我们可以将行读入数组。当NR!=FNR我们检查是否设置了该行的数组时。

$ cat abc.txt                                                      
abcd
xyz
pqrs
$ cat mno.txt                                                      
zzon
xyz
mkno
abcd
$ awk 'NR==FNR{a[$0]++};NR!=FNR && a[$0]' abc.txt  mno.txt         
xyz
abcd

相反,我们可以否定模式以打印那些不在 abc.txt

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt       
zzon
mkno

如果我们想打印那些我们可以使用的计数sortwc

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt | sort -u | wc -l         
2

我认为您的做法是错误的。据我理解这个问题,OP要计算(大小)的差集abc.txt- mno.txt这是{xyz, pqrs}
大卫·佛斯特

2

如果其中一个单词列表未排序,则使用有效的集合数据结构记住常用单词会更快。

蟒蛇

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as minuend_file:
    minuend = frozenset(map(str.rstrip, minuend_file))
with open(sys.argv[2]) as subtrahend_file:
    subtrahend = frozenset(map(str.rstrip, subtrahend_file))

difference = minuend - subtrahend
#print(*difference, sep='\n') # This prints the content of the set difference
print(len(difference)) # This prints the magnitude of the set difference

用法:

python3 set-difference.py abc.txt mno.txt

Python(效率更高)

如果您想为中间存储和运行时间节省一点内存,可以使用以下稍微难懂的程序:

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as minuend_file:
    minuend = set(map(str.rstrip, minuend_file))
with open(sys.argv[2]) as subtrahend_file:
    subtrahend = map(str.rstrip, subtrahend_file)
    minuend.difference_update(subtrahend)
    difference = minuend
    del minuend

#print(*difference, sep='\n') # This prints the content of the set difference
print(len(difference)) # This prints the magnitude of the set difference

性能

给定abc.txtmno.txt带有1个mio未排序行,每个行包含10个随机ASCII数字字符(有关设置,请参见Oli的答案):

$ time python3 set-difference.py abc.txt mno.txt
user    0m10.453s

$ export LC_COLLATE=C
$ time sort abc.txt > abc_sorted.txt
user    0m10.652s
$ time sort mno.txt > mno_sorted.txt
user    0m10.767s
$ time comm -23 abc_sorted.txt mno_sorted.txt | wc -l
9989882
user    0m1.600s

总计:23秒

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.