我有两个文件:
abc.txt
abcd
xyz
pqrs
mno.txt
zzon
mkno
abcd
- 我想检查文件mno.txt中是否有“ abcd” 。
- 如果“ abcd”在abc.txt中排在首位,则也不必在mno.txt中排在首位。
- 两个文件中都有数千个这样的ID。
- 我还想检查mno.txt中有多少id不在abc.txt中。
我怎样才能做到这一点 ?
我有两个文件:
abc.txt
abcd
xyz
pqrs
mno.txt
zzon
mkno
abcd
我怎样才能做到这一点 ?
Answers:
如果您的目标是找到常见或罕见的行,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上执行此操作,则将需要更慢的周转时间,并且差异会增加到实际上很重要的程度。
得到一个清单:
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
反向搜索fgrep
,egrep
交替理应弃用(赞成grep -F
,grep -E
-尽管我不知道有任何人相信,他们将永远消失
-x
时有必要使用-F
吗?
abcdef
该计数是否应与匹配或不匹配abcd
?
我们可以使用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
如果我们想打印那些我们可以使用的计数sort
和wc
:
$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt mno.txt | sort -u | wc -l
2
abc.txt
- mno.txt
这是{xyz, pqrs}
。
如果其中一个单词列表未排序,则使用有效的集合数据结构记住常用单词会更快。
#!/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
如果您想为中间存储和运行时间节省一点内存,可以使用以下稍微难懂的程序:
#!/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.txt
并mno.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秒
grep -cxvFf abc.txt mno.txt
?