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

lal*_*lli 117 bash scripting sh

我有一个文件f1:

line1
line2
line3
line4
..
..
Run Code Online (Sandbox Code Playgroud)

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

line2
line8
..
..
Run Code Online (Sandbox Code Playgroud)

我想的东西catsed,这甚至还没有接近我所预期的.我怎样才能做到这一点?

gab*_*uzo 141

grep -v -x -f f2 f1 应该做的伎俩.

说明:

  • -v 选择不匹配的行
  • -x 仅匹配整行
  • -f f2 从中获取模式 f2

人们可以改用grep -F匹配固定的字符串fgrep,而不是模式(如果你想删除一个"你所看到的,如果你得到了什么"的方式行,而不是治疗的线条f2为正则表达式模式).

  • 这具有O(n²)复杂度,并且一旦文件包含多于几K行,将开始花费数小时来完成. (21认同)
  • 确定哪些SO建议的algorythms具有O(n ^ 2)复杂度仅具有O(n)复杂度,但仍然需要数小时才能竞争. (9认同)
  • 我只是尝试了两个~2k行的文件,它被操作系统杀死(授予,这是一个不那么强大的VM,但仍然). (2认同)
  • 我喜欢它的优雅;我更喜欢 Jona Christopher Sahnwal 的回答速度。 (2认同)

Ign*_*ams 54

改为尝试comm(假设f1和f2已经"已经排序")

comm -2 -3 f1 f2
Run Code Online (Sandbox Code Playgroud)

  • 当然,您可以使用进程替换来对文件进行排序:`comm -2 -3 <(sort f1)<(sort f2)` (8认同)
  • 我不确定`comm`是解决方案的问题并不表示`f1`中的行是排序的,这是使用`comm`的先决条件 (5认同)
  • 当它起作用时(输入文件已排序),速度非常快! (2认同)

Pau*_*ce. 13

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

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

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

算法复杂度可能是O(n)(exclude-these.txt size)+ O(n)(from-this.txt size)


jcs*_*ica 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更快,我也更喜欢保持原始顺序.


kur*_*umi 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
Run Code Online (Sandbox Code Playgroud)

具有O(N ^ 2)复杂度。如果您想关心性能,这是另一个版本

b=File.read("file2").split
a=File.read("file1").split
(a-b).each {|x| puts x}
Run Code Online (Sandbox Code Playgroud)

它使用散列来实现减法,复杂度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)
$
Run Code Online (Sandbox Code Playgroud)

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

  • 无需如此防御,这并不是@ user576875否决了您的答案或其他任何东西。:-) (3认同)