【问题标题】:Non-grep method to remove lines from a file where a string appears in another file用于从文件中删除字符串出现在另一个文件中的行的非 grep 方法
【发布时间】:2017-09-19 12:38:19
【问题描述】:

我知道之前已经回答了一些与此类似的问题,但我还没有找到我想要的确切答案(并且尝试了所提议的解决方案的变体)。希望这是一个简单的问题。

我有一个制表符分隔的文件 (file.txt),它有 10 列和大约 50 万行,简化后如下所示:

ID     Col1      Col2     Col3
a        4        2        8
b        5        6        1
c        8        4        1
d        3        5        9
e        8        5        2

我想删除第一列 (ID) 中出现“b”和“d”的所有行。我想要的输出是:

ID     Col1      Col2     Col3
a        4        2        8
c        8        4        1
e        8        5        2

在我的输出文件中维护 ID 的顺序很重要。

实际上,我想删除大约 100,000 行。因此,我有一个参考文件 (referencefile.txt),其中列出了我想从 file.txt 中删除的所有 ID。在本例中,参考文件将简单地在连续的行中包含“b”和“d”。

我目前正在使用 grep,虽然它可以工作,但它被证明非常缓慢。

grep -v -f referencefile.txt file.txt

有没有办法使用 awk 或 sed(或其他任何东西)来加速这个过程?

非常感谢。

AB

【问题讨论】:

    标签: awk sed grep


    【解决方案1】:

    使用awk

    awk 'FNR>1 && ($1 == "b" || $1 == "d"){ next } 1' infile
    
    # OR
    
    awk 'FNR>1 && $1 ~ /^([bd])$/{ next } 1' infile
    
    # To exclude line from infile, where list of ids from id_lists 
    # exists in first field of infile
    awk 'FNR==NR{ids[$1];next}FNR>1 && ($1 in ids){next}1' id_lists infile
    
    # To include line from infile, where list of ids from id_lists 
    # exists in first field of infile
    awk 'FNR==NR{ids[$1];next}FNR==1 || ($1 in ids)' id_lists infile
    

    测试结果:

    输入

    $ cat infile 
    ID     Col1      Col2     Col3
    a        4        2        8
    b        5        6        1
    c        8        4        1
    d        3        5        9
    e        8        5        2
    

    输出

    $ awk 'FNR>1 && $1 ~ /^([bd])$/{ next } 1' infile
    ID     Col1      Col2     Col3
    a        4        2        8
    c        8        4        1
    e        8        5        2
    
    $ awk 'FNR>1 && ($1 == "b" || $1 == "d"){ next } 1' infile
    ID     Col1      Col2     Col3
    a        4        2        8
    c        8        4        1
    e        8        5        2
    

    但是“b”和“d”是为了说明的目的,我实际上有 我需要删除大约 100,000 个 ID。所以我想要所有这些ID 列在单独的文件中(referencefile.txt)

    如果你有如下 id 列表的文件,那么

    排除 id 列表

    $ cat id_lists
    a
    b
    
    $ awk 'FNR==NR{ids[$1];next}FNR>1 && ($1 in ids){next}1' id_lists infile
    ID     Col1      Col2     Col3
    c        8        4        1
    d        3        5        9
    e        8        5        2
    

    包含 id 列表

    $ awk 'FNR==NR{ids[$1];next}FNR==1 || ($1 in ids)' id_lists infile
    ID     Col1      Col2     Col3
    a        4        2        8
    b        5        6        1
    

    【讨论】:

    • 感谢 Akshay,但“b”和“d”仅用于说明目的,实际上我需要删除大约 100,000 个 ID。所以我希望所有这些 ID 都列在一个单独的文件 (referencefile.txt) 中。
    • @GB44444:我添加了 2 个解决方案,一个用于包含,另一个用于排除
    • 完美。非常感谢!
    【解决方案2】:

    有一些方法可以加速 grep 本身。

    我建议:

    • -F-f referencefile.txt 中的输入视为固定字符串而不是正则表达式。

    • -w匹配单词

    • 可能是 LC_ALL=C - 使用 LC_ALL 环境变量来指示 grep 使用 ascii 而不是 UTF-8

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多