删除另一个文件中的一个文件的行

我有一个文件f1

 line1 line2 line3 line4 .. .. 

我想删除另一个文件f2所有行:

 line2 line8 .. .. 

我用cat和东西做了一些尝试,甚至没有达到我想要的。 我怎样才能做到这一点?

grep -v -x -f f2 f1应该可以做到。

说明:

  • -vselect不匹配的行
  • -x仅匹配整行
  • -f f2f2获取模式

我们可以使用-F f2来匹配-F f2中的固定string ,而不是模式 (如果你想删除“你看到的是什么”的方式,而不是将f2的行作为正则expression式)。

尝试通讯,而不是(假设f1和f2是“已经sorting”)

 comm -2 -3 f1 f2 

对于不太大的排除文件,可以使用AWK的关联数组。

 awk 'NR == FNR { list[tolower($0)]=1; next } { if (! list[tolower($0)]) print }' exclude-these.txt from-this.txt 

输出的顺序与“from-this.txt”文件的顺序相同。 如果需要的话, tolower()函数会使其不区分大小写。

algorithm复杂度可能是O(n)(exclude-these.txt大小)+ O(n)(from-this.txt大小)

类似于丹尼斯·威廉姆森的答案(主要是语法上的变化,例如明确地设置文件号码而不是NR == FNR技巧):

awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 exclude-these.txt f=2 from-this.txt

访问r[$0]为该行创build条目,不需要设置值。

假设awk使用一个哈希表,其查询常数和平均更新时间不变,其时间复杂度为O(n + m),其中n和m是文件的长度。 在我的情况下,n是2500万和14000。 awk的解决scheme比sorting要快得多,而且我也喜欢保持原来的顺序。

如果你有Ruby(1.9+)

 #!/usr/bin/env ruby b=File.read("file2").split open("file1").each do |x| x.chomp! puts x if !b.include?(x) end 

其中有O(N ^ 2)的复杂性。 如果你想关心性能,这是另一个版本

 b=File.read("file2").split a=File.read("file1").split (ab).each {|x| puts x} 

(n)(大小a)+ O(n)(b的大小)

这里有一个基准,用户576875提供,但有10万行,

 $ for i in $(seq 1 100000); do echo "$i"; done|sort --random-sort > file1 $ for i in $(seq 1 2 100000); do echo "$i"; done|sort --random-sort > file2 $ time ruby test.rb > ruby.test real 0m0.639s user 0m0.554s sys 0m0.021s $time sort file1 file2|uniq -u > sort.test real 0m2.311s user 0m1.959s sys 0m0.040s $ diff <(sort -n ruby.test) <(sort -n sort.test) $ 

diff被用来显示所产生的2个文件之间没有差异。

似乎是适合SQLiteshell的工作:

 create table file1(line text); create index if1 on file1(line ASC); create table file2(line text); create index if2 on file2(line ASC); -- comment: if you have | in your files then specify “ .separator ××any_improbable_string×× ” .import 'file1.txt' file1 .import 'file2.txt' file2 .output result.txt select * from file2 where line not in (select line from file1); .q 

你用sed来试试这个吗?

 sed 's#^#sed -i '"'"'s%#g' f2 > f2.sh sed -i 's#$#%%g'"'"' f1#g' f2.sh sed -i '1i#!/bin/bash' f2.sh sh f2.sh 

一些其他的答案之间的时间比较:

 $ for n in {1..10000}; do echo $RANDOM; done > f1 $ for n in {1..10000}; do echo $RANDOM; done > f2 $ time comm -23 <(sort f1) <(sort f2) > /dev/null real 0m0.019s user 0m0.023s sys 0m0.012s $ time ruby -e 'puts File.readlines("f1") - File.readlines("f2")' > /dev/null real 0m0.026s user 0m0.018s sys 0m0.007s $ time grep -xvf f2 f1 > /dev/null real 0m43.197s user 0m43.155s sys 0m0.040s 

sort f1 f2 | uniq -u sort f1 f2 | uniq -u甚至不是一个对称的区别,因为它删除了在任何一个文件中出现多次的行。

通信也可以用于标准input和这里的string:

 echo $'a\nb' | comm -23 <(sort) <(sort <<< $'c\nb') # a