如何从另一个文件A中删除文件B上出现的行?

slh*_*hck 144 linux shell diff grep sed

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

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

所以,如果文件A包含:

A
B
C
Run Code Online (Sandbox Code Playgroud)

和文件B包含:

B    
D
E
Run Code Online (Sandbox Code Playgroud)

然后文件A应该留下:

A
C
Run Code Online (Sandbox Code Playgroud)

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

任何帮助将非常感激!有人肯定会想出一个聪明的单行,但我不是shell专家.

The*_*aul 187

comm -23 file1 file2
Run Code Online (Sandbox Code Playgroud)

-23会抑制两个文件中的行,或仅抑制文件2中的行.文件必须进行排序(它们在您的示例中)但如果不是,则-23先将它们通过...

请参见此处手册页

  • `comm -23 file1 file2> file3`将把file1中的内容输出到file3,而不是file2.然后`mv file3 file1`最终将清除file1中的冗余内容. (6认同)
  • 或者,使用`comm -23 file1 file2 | 海绵文件1`。无需清理。 (3认同)

Cir*_*四事件 71

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

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

例:

cat <<EOF > A
b
1
a
0
01
b
1
EOF

cat <<EOF > B
0
1
EOF

grep -Fvxf B A
Run Code Online (Sandbox Code Playgroud)

输出:

b
a
01
b
Run Code Online (Sandbox Code Playgroud)

说明:

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

对于预先排序的文件,此方法比其他方法慢,因为它更通用.如果速度也很重要,请参阅:快速查找一个文件中不在另一个文件中的行?

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


kar*_*kfa 48

拯救!

此解决方案不需要排序输入.你必须先提供fileB.

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

回报

A
C
Run Code Online (Sandbox Code Playgroud)

它是如何工作的?

NR==FNR{a[$0];next} idiom用于将第一个文件存储在关联数组中,作为以后"包含"测试的键.

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

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

!($0 in a)我们现在在下一个文件中, in是一个包含测试,这里它检查当前行是否在我们从第一个文件的第一步填充的集合中,!否定条件.这里缺少的是动作,默认情况下{print}通常不会明确写入.

请注意,现在可以使用此功能删除列入黑名单的单词.

$ awk '...' badwords allwords > goodwords
Run Code Online (Sandbox Code Playgroud)

稍作修改,它可以清理多个列表并创建清理版本.

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

  • @Sxilderik感谢提醒,我补充说明. (3认同)

Pau*_*ce. 17

另一种做同样事情的方法(也需要排序输入):

join -v 1 fileA fileB
Run Code Online (Sandbox Code Playgroud)

在Bash中,如果文件未预先排序:

join -v 1 <(sort fileA) <(sort fileB)
Run Code Online (Sandbox Code Playgroud)


aec*_*aec 6

除非对文件进行排序,否则可以执行此操作

diff file-a file-b --new-line-format="" --old-line-format="%L" --unchanged-line-format="" > file-a
Run Code Online (Sandbox Code Playgroud)

--new-line-format适用于文件b中的行但不适 --old-..用于文件a中的行而不是b --unchanged-..中的行适用于两者中的行. %L使它完全打印出来.

man diff
Run Code Online (Sandbox Code Playgroud)

更多细节


pea*_*eak 6

对于非常大的文件,@ karakfa很好的答案的这种改进可能会明显更快。与该答案一样,两个文件都不需要排序,但是借助awk的关联数组可以确保速度。仅查找文件保留在内存中。

这种表述还允许比较中仅使用输入文件中的一个特定字段($ 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}'
Run Code Online (Sandbox Code Playgroud)

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