如何使用 awk 过滤表

如何使用 awk 过滤表

我想知道如何根据每个感兴趣的列中的特定值来过滤具有多个列的表。

我这里有这个例子:

    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。

相关内容