首页 文章

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

提问于
浏览
117

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

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

那么,如果文件A包含:

A
B
C

和文件B包含:

B    
D
E

然后文件A应该留下:

A
C

现在我知道这是一个可能经常被问到的问题,但是我发现one command online给了我错误的分隔符 .

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

8 回答

  • 17

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

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

    --new-line-format 适用于文件b中但不包含在 --old-.. 中的行适用于文件a但不在b中的行 --unchanged-.. 适用于两者中的行 . %L 使得线条打印完全正确 .

    man diff
    

    更多细节

  • 2
    comm -23 file1 file2
    

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

    man page here

  • 34

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

    • 适用于未排序的文件

    • 维护订单

    • is POSIX

    例:

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

    输出:

    b
    a
    01
    b
    

    说明:

    • -F :使用文字字符串而不是默认的BRE

    • -x :仅考虑与整行匹配的匹配项

    • -v :打印不匹配

    • -f file :从给定文件中获取模式

    对于预先排序的文件,此方法比其他方法慢,因为它更通用 . 如果速度也很重要,请参阅:Fast way of finding lines in one file that are not in another?

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

  • 6

    拯救!

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

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

    回报

    A
    C
    

    How does it work?

    NR == FNR {a [$ 0]; next} idiom用于将第一个文件存储在关联数组中,作为后续“包含”测试的键 . NR == FNR正在检查我们是否正在扫描第一个文件,其中全局行计数器(NR)等于当前文件行计数器(FNR) . a [$ 0]将当前行作为键添加到关联数组中,注意这个行为就像一个集合,其中不会有任何重复值(键)!($ 0 in a)我们现在在下一个文件中( s),in是一个包含测试,这里检查当前行是否在我们在第一个文件的第一步中填充的集合中!否定了这个条件 . 这里缺少的是动作,默认情况下是,通常不会明确写入 .

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

    $ awk '...' badwords allwords > goodwords
    

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

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

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

    join -v 1 fileA fileB
    

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

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

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

    (这种方法的另一个优点是很容易修改比较标准,例如修剪前导和尾随空白区域 . )

  • 55

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

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

    这适用于未排序的文件 .

相关问题