我有一个文件f1
:
line1
line2
line3
line4
..
..
我想删除另一个文件f2
中的所有行:
line2
line8
..
..
我尝试使用cat
和sed
,但这与我的意图并不相符。我怎么能这样做?
答案 0 :(得分:131)
grep -v -x -f f2 f1
应该可以解决问题。
说明:
-v
选择不匹配的行-x
仅匹配整行-f f2
从f2
可以使用grep -F
或fgrep
来匹配来自f2
的固定字符串而不是模式(如果您需要删除“你所看到的是什么”的方式,而不是将f2
中的行视为正则表达式模式。)
答案 1 :(得分:48)
尝试使用comm(假设f1和f2已经“已经排序”)
comm -2 -3 f1 f2
答案 2 :(得分:12)
对于不太大的排除文件,可以使用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)(不包括--the.txt大小)+ O(n)(来自-t.txt大小)
答案 3 :(得分:10)
类似于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更快,我也更喜欢保留原始订单。
答案 4 :(得分:5)
如果你有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提供,但有100K行,以上:
$ 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个文件之间没有差异。
答案 5 :(得分:4)
其他各种答案之间的时间比较:
$ 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
答案 6 :(得分:2)
似乎是适合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
答案 7 :(得分:1)
您是否使用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
答案 8 :(得分:0)
这不是一个“编程”答案,但这是一个快速而肮脏的解决方案:只需转到http://www.listdiff.com/compare-2-lists-difference-tool。
显然不适用于海量文件,但对我有用。一些注意事项: