非grep方法从字符串出现在另一个文件中的文件中删除行

时间:2017-09-19 12:38:20

标签: awk sed grep

我知道有一些类似的问题已经得到了回答,但我还没有找到我想要的东西(并尝试了所提出的解决方案的变体)。希望这是一个简单的问题。

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

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

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

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

2 个答案:

答案 0 :(得分:2)

使用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
  

但&#34; b&#34;和&#34; d&#34;是为了说明的目的,我实际上有   我需要移除大约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

答案 1 :(得分:0)

有很多方法可以加快grep本身的速度。

我建议:

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

  • -w匹配单词

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