我有一个制表符分隔的文本文件,希望有效删除符合以下任一条件的整行:
ALT
列中的值等于.
NA00001
列中的值和后续列中两个分隔符|
或/
之前和之后具有相同数字的值,例如0|0
,1|1
,2/2
等。示例输入文件如下:
CHROM POS ID REF ALT QUAL FILTER INFO FORMAT NA00001 NA00002 NA00003
20 14370 rs6054257 G A 29 PASS NS=3;DP=14;AF=0.5;DB;H2 GT:GQ:DP:HQ 0|0:48:1:51,51 0|0:48:8:51,51 1/1:43:5:.,.
20 17330 . T A 3 q10 NS=3;DP=11;AF=0.017 GT:GQ:DP:HQ 0|0:49:3:58,50 0|1:3:5:65,3 0/0:41:3
20 1110696 rs6040355 A G,T 67 PASS NS=2;DP=10;AF=0.333,0.667;AA=T;DB GT:GQ:DP:HQ 1|2:21:6:23,27 2|1:2:0:18,2 2/2:35:4
20 1110696 rs6040360 A . 67 PASS NS=2;DP=10;AF=0.333,0.667;AA=T;DB GT:GQ:DP:HQ 1|2:21:6:23,27 2|1:2:0:18,2 2/2:35:4
示例输出文件是:
CHROM POS ID REF ALT QUAL FILTER INFO FORMAT NA00001 NA00002 NA00003
20 17330 . T A 3 q10 NS=3;DP=11;AF=0.017 GT:GQ:DP:HQ 0|0:49:3:58,50 0|1:3:5:65,3 0/0:41:3
20 1110696 rs6040355 A G,T 67 PASS NS=2;DP=10;AF=0.333,0.667;AA=T;DB GT:GQ:DP:HQ 1|2:21:6:23,27 2|1:2:0:18,2 2/2:35:4
答案 0 :(得分:2)
您的示例似乎不包含符合“ALT
列中等于.
”条件的值的行,或者不符合符合第二个标准(标题行除外)。所以我在你的例子中添加了一些我自己的测试线;我希望我理解你的标准。
通过测试特定字段可以很容易地匹配第一个标准,如果我们在awk脚本中使用像awk这样的东西:$5 == "." {next}
会跳过该行。只使用正则表达式也非常简单:^[^^I]*^I[^^I]*^I[^^I]*^I[^^I]*^I\.^I
,其中^I
是制表符,匹配只有“。”的行。在第五个(ALT)字段中。
使用严格的正则表达式,您无法直接表达“[分隔符]之前和之后的相同数字”。您必须使用具有特定值的子表达式的替换来执行此操作:0[|/]0|1[|/]1|2[|/]2
...但是只有10位数字,因此这不是特别繁琐。因此,例如,您可以使用一个长egrep命令行进行此过滤:
egrep -v '^[^^I]*^I[^^I]*^I[^^I]*^I[^^I]*^I\.^I|0[|/]0|1[|/]1|2[|/]2|3[|/]3|4[|/]4|5[|/]5|6[|/]6|7[|/]7|8[|/]8|9[|/]9' input-file
显然,这不是您想要定期手工打字的东西,并不适合维护。一个小awk脚本更好:
#! /usr/bin/awk -f
# Skip lines with "." in the fifth (ALT) field
$5 == "." {next}
# Skip lines with the same digit before and after the delimiter in any field
/0[|/]0/ {next}
/1[|/]1/ {next}
/2[|/]2/ {next}
/3[|/]3/ {next}
/4[|/]4/ {next}
/5[|/]5/ {next}
/6[|/]6/ {next}
/7[|/]7/ {next}
/8[|/]8/ {next}
/9[|/]9/ {next}
# Copy all other lines to the output
{print}
为了便于阅读,我将各个数字检查作为单独的awk语句。
使用扩展正则表达式(ERE),可以直接在分隔符之前和之后表达“相同的字符”,使用反向引用。应谨慎使用反向引用,因为它们可以创建病态性能特征;当然,你必须使用支持它们的语言,例如perl。 POSIX awk和Gnu gawk没有。这是一个处理第二个标准的Perl单行程序:
LINE: while (<STDIN>) { next LINE if /(\d)[|\/]\g1/; print }
这可能不是很好的Perl - 我几乎从不使用该语言 - 但它在我的测试中有效。 (\d)
匹配并记住分隔符前面的数字,\g1
匹配分隔符后记住的数字。
答案 1 :(得分:1)
perl -alnE '$F[4] eq "." and
$F[9] =~ m!(\d)[|/]\1! and
$F[10] =~ m!(\d)[|/]\1! and
say'
更新:抱歉OP要求对方......
perl -alnE 'say unless (
$f[4] eq "." or
( $F[9] =~ m!(\d)[|/]\1! and
$F[10] =~ m!(\d)[|/]\1! and
$F[11] =~ m!(\d)[|/]\1!
)
)'
或同等的
perl -ane 'next if ( $f[4] eq ".");
next if ( $F[9] =~ m!(\d)[|/]\1! and
$F[10] =~ m!(\d)[|/]\1! and
$F[11] =~ m!(\d)[|/]\1! );
print '