我想知道如何根据每个感兴趣的列中的特定值来过滤具有多个列的表。
我这里有这个例子:
Chr1 16644 0 0 1 1
Chr1 16645 0 0 1 1
Chr1 16646 0 0 1 1
Chr1 16647 0 0 1 1
Chr1 16648 0 0 1 1
Chr1 16649 0 0 1 1
Chr1 16650 0 0 1 1
Chr1 16651 0 0 1 1
Chr1 16782 0 0 0 0
Chr1 16783 0 0 0 0
Chr1 16784 0 0 0 0
Chr1 16785 0 0 0 0
Chr1 16786 0 0 1 1
Chr1 16787 0 0 1 1
Chr1 16788 0 0 1 1
Chr1 16789 0 0 1 1
Chr1 16790 0 0 1 1
我想删除所有第 3、4、5、6 列中包含零的行。
我已经尝试过了
cat STARsamples_read_depth.txt | awk '$3 != 0 && $4 != 0&& $5 != 0 && $6 != 0' | less
但它也删除了其中只有某些列为零的行,而不是所有四列!
有办法做到吗?
谢谢
阿萨
答案1
使用任何 awk,您都可以测试您感兴趣的字段的串联是否会产生非零数字:
$ awk '($3$4$5$6)+0' file
Chr1 16644 0 0 1 1
Chr1 16645 0 0 1 1
Chr1 16646 0 0 1 1
Chr1 16647 0 0 1 1
Chr1 16648 0 0 1 1
Chr1 16649 0 0 1 1
Chr1 16650 0 0 1 1
Chr1 16651 0 0 1 1
Chr1 16786 0 0 1 1
Chr1 16787 0 0 1 1
Chr1 16788 0 0 1 1
Chr1 16789 0 0 1 1
Chr1 16790 0 0 1 1
或者如果您出于某种原因想单独测试每个字段,那么:
$ awk '{for (i=3; i<=6; i++) if ($i != 0) { print; next } }' file
Chr1 16644 0 0 1 1
Chr1 16645 0 0 1 1
Chr1 16646 0 0 1 1
Chr1 16647 0 0 1 1
Chr1 16648 0 0 1 1
Chr1 16649 0 0 1 1
Chr1 16650 0 0 1 1
Chr1 16651 0 0 1 1
Chr1 16786 0 0 1 1
Chr1 16787 0 0 1 1
Chr1 16788 0 0 1 1
Chr1 16789 0 0 1 1
Chr1 16790 0 0 1 1
如果您的输入可能不是问题中所示的整数(请参阅注释),则使用上面的第二个脚本,或者您可以将其设置为字符串,而不是连接上的数字比较:
awk '($3$4$5$6) != "0000"' file
答案2
正如@Devon 在评论中提到的:使用||
而不是&&
.
原因是你想要显示至少在哪里的行一第 3、4、5、6 列的值与零不同。
这是另一种理解方式。您正在尝试删除那些列全为零的行。让我们从相反的角度开始:打印所有这些列都为 0 的行。这很简单:
awk '$3 == 0 && $4 == 0 && $5 == 0 && $6 == 0'
现在你想要倒置此语句:显示所有行不符合上面的条件。所以你只需否定这个陈述。
awk '(!($3 == 0 && $4 == 0 && $5 == 0 && $6 == 0))'
顺便说一句,上面的命令也可以满足您的要求。
无论如何,根据逻辑否定规则, 命题的否定“A和乙”是“不是A或者不是B”。所以要否定这个说法:
$3 == 0 && $4 == 0 && $5 == 0 && $6 == 0
您需要否定每个表达式,并转换所有“和”运营商“或者”。
$3 != 0 || $4 != 0 || $5 != 0 || $6 != 0
现在您可以更好地理解为什么您的命令不起作用。您使用的语句的否定将是:
$3 == 0 || $4 == 0 || $5 == 0 || $6 == 0
这意味着它将删除至少在其中的所有行一列(并非全部)为零。
答案3
使用awk
:
$ awk '!/(\s+0){4}$/' file
Or
$ awk '!/([[:space:]]+0){4}$/' file
第二个命令需要 POSIX awk。
删除包含所有字段(即$3
、$4
、$5
和$6
为零)的记录。正如@EdMorton 所建议的
$ awk '{ x=4;for(i=3;i<=6;i++) if ($i==0) {x--;} }x' file
$3
如果、$4
、$5
和等字段之一$6
为零,则删除包含该字段的记录。
$ awk '{ x=1;for(i=3;i<=6;i++) if ($i==0) {x=0;break;} }x'
for循环(i=3;i<=6;i++)
是因为过滤字段3,4,5,6。