例如,如果这是file1:
line1 line2 line3
这是file2:
line1 line4 line5
然后我的结果/输出应该是:
line2 line3
这工作:
grep -v -f file2 file1
但它是非常,非常缓慢,当我使用在我的大文件。
我怀疑有一个很好的方法来做到这一点使用diff(),但输出应该只是行,没有别的,我似乎找不到一个开关。
任何人都可以帮助我找到一个快速的方式,这样做,使用bash和基本的linux二进制文件?
编辑:为了跟进我自己的问题,这是我发现到目前为止使用diff()的最好的方式:
diff file2 file1 | grep '^>' | sed 's/^>\ //'
当然,必须有更好的方法吗?
diff --new-line-format="" --unchanged-line-format="" file1 file2
输入文件应该排序为这个工作。使用bash(和zsh),您可以使用进程替换<():
diff --new-line-format="" --unchanged-line-format="" <(sort file1) <(sort file2)
在上面的新的和不变的行被抑制,所以只有改变(即在你的情况下删除行)输出。
说明
选项–new-line-format,–old-line-format和–unchanged-line-format允许您控制diff格式化差异的方式,类似于printf格式说明符。这些选项分别格式化新(添加),旧(删除)和不变的行。将一个设置为空“”防止输出这种线。
如果您熟悉统一差异格式,您可以使用以下部分重新创建:
diff --old-line-format="-%L" --unchanged-line-format=" %L" \ --new-line-format="+%L" file1 file2
%L说明符是正在讨论的行,我们前面每个都有“”“ – ”或“”,像diff -u
(注意,它只输出差异,它缺少每个分组变化顶部的—和@@线)。
你也可以使用它来做其他有用的事情,如number each line与%dn。
diff方法(与其他建议comm和join一起)只产生具有排序输入的预期输出,但您可以使用<(sort ...)来排序。这里有一个简单的awk(nawk)脚本(受KonsoleBox答案中链接到的脚本的启发),它接受任意排序的输入文件,并按照它们在file1中出现的顺序输出缺少的行。
# 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的整个内容逐行存储在行号索引数组ll1 []中,并将file2的整个内容逐行存储在行内容索引关联数组ss2 []中。读取这两个文件后,遍历ll1并使用in运算符确定file1中的行是否存在于file2中。 (如果有重复,这将有不同的输出到diff方法。)
如果文件足够大,以至于存储它们都会导致内存问题,您可以通过仅存储file1并在读取file2时删除匹配项来交换cpu的内存。
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的全部内容存储在两个数组中,一个用行号ll1 []索引,一个用行内容ss1 []索引。然后,当读取file2时,从ll1 []和ss1 []中删除每个匹配行。最后,输出来自file1的剩余行,保留原始顺序。
在这种情况下,如上所述的问题,你也可以使用GNU split(过滤是一个GNU扩展)分割和征服,重复运行与file1的块和读取file2每次完全:
split -l 20000 --filter='gawk -f linesnotin.awk - file2' < file1
注意使用和放置 – 在gawk命令行上的stdin。这是通过从每个调用20000行的块中的file1拆分提供的。
对于非GNU系统上的用户,几乎肯定有一个GNU coreutils包可以获得,包括作为Apple Xcode工具的一部分在OSX上提供GNU diff,awk,虽然只有一个POSIX / BSD拆分,而不是一个GNU版本。