根据单独文件中列出的值从文本文件中删除观察结果

时间:2016-03-12 02:51:35

标签: bash shell unix awk

我有一个~15,000,000行文本文件(文件A),其中包含以下列:

1   1:693731    0   693731  G   A
1   1:706992    0   706992  T   C
1   1:707014    0   707014  C   A
1   1:715142    0   715142  T   G
1   1:724721    0   724721  A   C
1   1:729679    0   729679  C   G
...

在一个单独的文件(文件B)中,我有一个我要从文件A中删除的约80,000个观察的列表:

1:706992
1:715142
1:729679
...

我想根据第2列中的值(文件B中列出)从文件A中删除行并打印输出。因此,输出文件应如下所示:

1   1:693731    0   693731  G   A
1   1:707014    0   707014  C   A
1   1:724721    0   724721  A   C

非常感谢任何输入。

3 个答案:

答案 0 :(得分:3)

单程awk解决方案:

awk 'NR==FNR { xclude[$0]++; next } !xclude[$2]' fileB fileA
  • NR==FNR { xclude[$0]++; next }仅处理来自第一个输入文件(fileB)的行,并将其行($0)存储为关联数组xclude的关键字非零值(凭借++)。

    • NR(整体行索引)仅等于第一个输入文件的FNR(输入文件特定行索引); next跳过脚本的其余部分并继续到下一个输入行。
  • 因此,
  • !xclude[$2]仅针对第二个输入文件(fileA)中的行进行评估,并且仅打印第二列值($2)不是的行({{ 1}})包含在排除数组!

    • 请注意,评估为true 的模式xclude会隐式打印手头的行,因为在没有关联操作的情况下这是awk的默认操作({{1} })。

在评论中,karakfa建议使用以下变体,从而绕过了对!xclude[$2]的需求:

{...}
  • 只需引用数组元素就会导致awk 隐式创建,所以++,尽管没有分配,创建一个元素,其键值为awk 'NR==FNR { xclude[$0]; next } !($2 in xclude)' fileB fileA

  • xclude[$0]然后只使用运算符$0测试数组$2 in xclude中的密钥$2存在(不测试,在这种情况下为空。)

答案 1 :(得分:1)

使用grep:

$ grep -vwFf fileB fileA
1   1:693731    0   693731  G   A
1   1:707014    0   707014  C   A
1   1:724721    0   724721  A   C

使用以下选项:

  • -v反向匹配:排除与
  • 匹配的行
  • -w单词匹配:仅匹配形成整个单词以避免子字符串匹配
  • -F固定字符串:不要将搜索字符串解释为正则表达式
  • -f从文件中读取:使用fileB作为要搜索的字符串列表

更详细,更易于阅读:

grep --invert-match --word-regexp --fixed-strings --file=fileB fileA

请注意,这不是一个普遍适用的解决方案,但可能适用于此数据集,假设第二列始终是唯一包含冒号的列。

答案 2 :(得分:0)

如果文件在密钥中排序,就像在样本中一样,您可以使用join

$ join -v1 -12 file1 file2 | awk -v OFS='\t' '{t=$2;$2=$1;$1=t}1'

1       1:693731        0       693731  G       A
1       1:707014        0       707014  C       A
1       1:724721        0       724721  A       C

您也可以使用-o选项进行列排序。