Fast way of finding lines in one file that are not in another?
我有两个大文件(文件名集)。 每个文件大约有30,000行。 我试图找到一种快速查找file1中不存在于file2中的行的方法。
例如,如果这是file1:
1 2 3 | line1 line2 line3 |
这是file2:
1 2 3 | line1 line4 line5 |
然后我的结果/输出应该是:
1 2 | line2 line3 |
这有效:
但是在我的大文件上使用它时非常非常慢。
我怀疑有一个很好的方法来使用diff(),但输出应该只是行,没有别的,我似乎无法找到一个开关。
任何人都可以帮我找到一个快速的方法,使用bash和基本的Linux二进制文件?
编辑:为了跟进我自己的问题,这是我到目前为止使用diff()找到的最好方法:
1 | diff file2 file1 | grep '^>' | sed 's/^>\ //' |
当然,必须有更好的方法吗?
comm命令("common"的缩写)可能很有用
1 2 3 4 5 6 7 8 | #find lines only in file1 comm -23 file1 file2 #find lines only in file2 comm -13 file1 file2 #find lines common to both files comm -12 file1 file2 |
您可以通过控制GNU
1 | diff --new-line-format="" --unchanged-line-format="" file1 file2 |
应对输入文件进行排序,以使其正常工作。使用
1 | diff --new-line-format="" --unchanged-line-format="" <(sort file1) <(sort file2) |
在上面新的和未改变的行被抑制,因此只输出(即你的情况下删除的行)。您也可以使用其他解决方案未提供的一些
说明
使用选项
如果您熟悉统一差异格式,则可以使用以下部分重新创建它:
1 2 | diff --old-line-format="-%L" --unchanged-line-format=" %L" \ --new-line-format="+%L" file1 file2 |
(请注意,它只输出差异,它缺少每个分组更改顶部的
您也可以使用它来执行其他有用的操作,例如使用
1 2 3 4 5 6 7 | # output lines in file1 that are not in file2 BEGIN { FS="" } # preserve whitespace (NR==FNR) { ll1[FNR]=$0; nl1=FNR; } # file1, index by lineno (NR!=FNR) { ss2[$0]++; } # file2, index by string END { for (ll=1; ll<=nl1; ll++) if (!(ll1[ll] in ss2)) print ll1[ll] } |
这将在行号索引数组
如果文件足够大以至于存储它们都会导致内存问题,则可以通过仅存储file1并在读取file2时删除匹配来交换CPU以获取内存。
1 2 3 4 5 6 7 8 9 10 | BEGIN { FS="" } (NR==FNR) { # file1, index by lineno and string ll1[FNR]=$0; ss1[$0]=FNR; nl1=FNR; } (NR!=FNR) { # file2 if ($0 in ss1) { delete ll1[ss1[$0]]; delete ss1[$0]; } } END { for (ll=1; ll<=nl1; ll++) if (ll in ll1) print ll1[ll] } |
上面将file1的全部内容存储在两个数组中,一个由行号
在这种情况下,如上所述的问题,你也可以使用GNU
1 | split -l 20000 --filter='gawk -f linesnotin.awk - file2' < file1 |
请注意在
对于非GNU系统上的用户,几乎可以肯定你可以获得一个GNU coreutils包,包括在OSX上作为Apple Xcode工具的一部分提供GNU
像konsolebox建议,海报grep解决方案
1 | grep -v -f file2 file1 |
如果只是添加
这些测试还包括
因此,不需要对输入进行排序的解决方案是快速,灵活(区分大小写等),并且(我认为)适用于任何POSIX系统:
1 | grep -F -x -v -f file2 file1 |
什么是排序和差异的速度?
1 2 3 | sort file1 -u > file1.sorted sort file2 -u > file2.sorted diff file1.sorted file2.sorted |
如果你缺少"花哨的工具",例如在一些最小的Linux发行版中,有一个只有
1 | cat includes.txt excludes.txt excludes.txt | sort | uniq --unique |
测试:
1 2 3 4 5 6 7 | seq 1 1 7 | sort --random-sort > includes.txt seq 3 1 9 | sort --random-sort > excludes.txt cat includes.txt excludes.txt excludes.txt | sort | uniq --unique # Output: 1 2 |
与
1 2 3 | $ join -v 1 -t '' file1 file2 line2 line3 |
你可以使用Python:
1 2 3 4 5 6 7 8 9 10 11 | python -c ' lines_to_remove = set() with open("file2","r") as f: for line in f.readlines(): lines_to_remove.add(line.strip()) with open("f1","r") as f: for line in f.readlines(): if line.strip() not in lines_to_remove: print(line.strip()) ' |
使用fgrep或向grep添加-F选项可能会有所帮助。但是为了更快的计算,你可以使用Awk。
您可以尝试以下Awk方法之一:
http://www.linuxquestions.org/questions/programming-9/grep-for-huge-files-826030/#post4066219
我通常这样做的方法是使用
我发现对我来说使用正常的if和for循环语句非常有效。
1 | for i in $(cat file2);do if [ $(grep -i $i file1) ];then echo"$i found">>Matching_lines.txt;else echo"$i missing">>missing_lines.txt ;fi;done |