我有一个很大的文件a(由电子邮件组成),每封邮件一行。我还有另一个文件B,其中包含另一组邮件。

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

因此,如果文件A包含:

A
B
C

文件B包含:

B    
D
E

那么文件A应该剩下:

A
C

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

任何帮助都将不胜感激!肯定有人会想出一个聪明的俏皮话,但我不是shell专家。


当前回答

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

join -v 1 fileA fileB

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

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

其他回答

对于非常大的文件,@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}'

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

你可以使用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)
'

你可以使用- diff fileA fileB | grep "^>" | cut -c3- > fileA

这也适用于没有排序的文件。

Awk来拯救!

这个解决方案不需要排序的输入。你必须先提供fileB。

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

返回

A
C

它是如何工作的?

NR==FNR{a[$0];next} idiom is for storing the first file in an associative array as keys for a later "contains" test. NR==FNR is checking whether we're scanning the first file, where the global line counter (NR) equals to the current file line counter (FNR). a[$0] adds the current line to the associative array as key, note that this behaves like a set, where there won't be any duplicate values (keys) !($0 in a) we're now in the next file(s), in is a contains test, here it's checking whether current line is in the set we populated in the first step from the first file, ! negates the condition. What is missing here is the action, which by default is {print} and usually not written explicitly.

注意,这现在可以用来删除列入黑名单的单词。

$ awk '...' badwords allwords > goodwords

只需稍作更改,它就可以清理多个列表并创建清理过的版本。

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

这是一个使用grep和lynx输出网站并删除导航元素的一行程序!你可以用cat FileA替换lynx,用FileB替换unwanted-elements.txt。

lynx -dump -accept_all_cookies -nolist -width 1000 https://stackoverflow.com/ | grep -Fxvf unwanted-elements.txt