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

我有一个大的文件A (由电子邮件组成),每个邮件一行。 我还有另外一个包含另一组邮件的文件B.

我将使用哪个命令从文件A中删除出现在文件B中的所有地址

所以,如果文件A包含:

A B C 

和文件B包含:

 BD E 

然后文件A应该留下:

 A C 

现在我知道这是一个可能经常被问到的问题,但是我只在网上find一个命令 ,给了我一个错误的分隔符。

任何帮助将非常感激! 有人肯定会提出一个聪明的一行,但我不是壳牌专家。

 comm -23 file1 file2 

-23抑制在两个文件中的行,或者只在文件2中。文件必须被sorting(它们在你的例子中),但是如果没有,通过先sortpipe道它们。

见这里的手册页

grep -Fvxf <lines-to-remove> <all-lines>

  • 适用于未sorting的文件
  • 维持秩序
  • 是POSIX

例:

 cat <<EOF > A b 1 a 0 01 b 1 EOF cat <<EOF > B 0 1 EOF grep -Fvxf BA 

输出:

 b a 01 b 

说明:

  • -F :使用文字string而不是默认的BRE
  • -x :只考虑匹配整行的匹配
  • -v :打印不匹配
  • -f file :从给定的文件中获取模式

这种方法比预先sorting的文件比其他方法慢,因为它更一般。 如果速度也很重要,请参阅: 快速find一个文件中不在另一个文件中的行的方法?

另见: https : //unix.stackexchange.com/questions/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another

awk来拯救!

这个解决scheme不需要sortinginput。 你必须先提供fileB。

 awk 'NR==FNR{a[$0];next} !($0 in a)' fileB fileA 

回报

 A C 

它是如何工作的?

NR==FNR{a[$0];next}习惯用于将第一个文件存储在关联数组中作为稍后“contains”testing的键。

NR==FNR正在检查我们是否正在扫描第一个文件,其中全局行计数器(NR)等于当前文件行计数器(FNR)。

a[$0]将当前行添加到关联数组中作为关键字,请注意,它的行为就像一个集合,其中不会有任何重复值(键)

!($0 in a)我们现在在下一个文件中, in是一个包含testing,这里是检查当前行是否在我们在第一个文件中填充的集合中! 否定条件。 这里缺less的是缺省为{print}并且通常不明确写入的操作。

请注意,这现在可以用来删除黑名单的话。

 $ awk '...' badwords allwords > goodwords 

稍作修改就可以清理多个列表并创build清理版本。

 $ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ... 

另一种做同样的事情(也需要sortinginput):

 join -v 1 fileA fileB 

在Bash中,如果文件没有预先sorting:

 join -v 1 <(sort fileA) <(sort fileB) 

除非你的文件被sorting,否则你可以这样做

 diff file-a file-b --new-line-format="" --old-line-format="%L" --unchanged-line-format="" > file-a 

--new-line-format是在文件b中,但不在--old-..中的行--old-..对于在文件a中但不在b中的行 – – --unchanged-..对于同时在两个行中的行。 %L使得它完全打印出来。

 man diff 

更多细节

对于非常大的文件来说,@ karakfa很好的答案的这种细化可能会明显更快。 与这个答案一样,这两个文件都不需要sorting,但速度是由awk的关联数组保证的。 只有查找文件被保存在内存中。

这个公式还允许在比较中仅使用input文件中的一个特定字段($ N)。

 # Print lines in the input unless the value in column $N # appears in a lookup file, $LOOKUP; # if $N is 0, then the entire line is used for comparison. awk -v N=$N -v lookup="$LOOKUP" ' BEGIN { while ( getline < lookup ) { dictionary[$0]=$0 } } !($N in dictionary) {print}' 

(这种方法的另一个优点是很容易修改比较标准,例如修剪前后空白。)

你可以使用Python:

 python -c ' lines_to_remove = set() with open("file B", "r") as f: for line in f.readlines(): lines_to_remove.add(line.strip()) with open("file A", "r") as f: for line in [line.strip() for line in f.readlines()]: if line not in lines_to_remove: print(line) '