我有一个~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
非常感谢任何输入。
答案 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}})包含在排除数组!
。
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
选项进行列排序。