我有一个文件f1
:
line1
line2
line3
line4
..
..
我想删除另一个文件中的所有行f2
:
line2
line8
..
..
我用cat
和尝试了一些东西sed
,这甚至与我的意图不符。我怎样才能做到这一点?
我有一个文件f1
:
line1
line2
line3
line4
..
..
我想删除另一个文件中的所有行f2
:
line2
line8
..
..
我用cat
和尝试了一些东西sed
,这甚至与我的意图不符。我怎样才能做到这一点?
Answers:
grep -v -x -f f2 f1
应该可以。
说明:
-v
选择不匹配的行-x
只匹配整行-f f2
从中获取模式 f2
人们可以改用grep -F
或fgrep
匹配固定的字符串从f2
,而不是模式(如果你想删除线的“如果你看到什么,你会得到什么”的方式,而不是治疗的线条f2
为正则表达式模式)。
grep
。如果f2
在开始搜索之前进行了适当的预处理,则搜索将仅花费O(n)时间。
尝试使用comm(假设f1和f2已“已排序”)
comm -2 -3 f1 f2
comm
解决方案的问题是否表示行f1
已排序是使用的先决条件comm
comm -2 -3 <(sort f1) <(sort 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()
如果需要,该函数使其不区分大小写。
算法复杂度可能为O(n)(不包括这些.txt的大小)+ O(n)(来自此.txt的大小)
exclude-these.txt
为空,则失败(即不产生任何输出)。在这种情况下,下面的@ jona-christopher-sahnwaldt答案有效。您还可以指定多个文件,例如awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 done.out failed.out f=2 all-files.out
与Dennis Williamson的答案类似(主要是语法上的更改,例如,显式设置文件号而不是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]
创建该行的条目,而无需设置值。
假设awk使用具有恒定查找和(平均)恒定更新时间的哈希表,则其时间复杂度将为O(n + m),其中n和m是文件的长度。就我而言,n约为2500万,m约为14000。awk解决方案比sort快得多,我也更喜欢保持原始顺序。
f
比清晰NR == FNR
,但这只是个问题。分配给散列的速度应该如此之快,以至于两个版本之间没有可测量的速度差异。我认为我错了复杂性-如果查找为常数,则更新也应为常数(平均)。我不知道为什么我认为更新将是对数的。我将编辑答案。
awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 empty.file done.out failed.out f=2 all-files.out
。而另一种awk
解决方案失败,排除文件为空,只能使用一个。
如果您有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
(a-b).each {|x| puts x}
使用散列来实现减法,复杂度O(n)(a的大小)+ O(n)(b的大小)
这是一个小基准,由user576875提供,但有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
用来显示生成的两个文件之间没有差异。
其他各种答案之间的一些时间比较:
$ 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
甚至不是对称差异,因为它删除了两个文件中多次出现的行。
comm也可以与stdin和以下字符串一起使用:
echo $'a\nb' | comm -23 <(sort) <(sort <<< $'c\nb') # a
似乎是适合SQLite shell的工作:
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
这不是一个“编程”的答案,但是这是一个快速而肮脏的解决方案:只需转到http://www.listdiff.com/compare-2-lists-difference-tool。
显然不适用于大文件,但对我有用。一些注意事项: