使用 awk 过滤行

使用 awk 过滤行

我有一个像这样的文件,它是制表符分隔的:

name    v1  v2  v3  v4
g1  4.5 2.3 2.1 0.2
g2  10  3   5   2.3
g3  7   2.5 2.8 3.9

只是向您展示了一个虚拟文件,其中有 5 列和 4 行(包括标题)。我想过滤掉行,如果特定行中的每一列的值 >= 2,则保留该行,否则将其删除。输出应如下所示:

name    v1  v2  v3  v4
g2  10  3   5   2.3
g3  7   2.5 2.8 3.9

我该如何使用 awk 来做到这一点?

答案1

AFAIK awk 没有办法显式地迭代字段。例如:

$ awk 'NR>1 {for(i=2;i<=NF;i++) if($i+0 < 2) next} 1' file
name    v1  v2  v3  v4
g2  10  3   5   2.3
g3  7   2.5 2.8 3.9

答案2

Steeldriver 已经提供了 awk 解决方案。这是一个 perl 版本(使用数组切片而不是 for 循环):

$ perl -lane 'print if ($.==1 || grep ($_ >= 2, @F) == $#F)' input.txt
name    v1  v2  v3  v4
g2  10  3   5   2.3
g3  7   2.5 2.8 3.9

这仅打印第一行(标题)以及所有数字字段的值大于或等于 2 的行。(非数字字段如g1g2将计算为0


注意:perl的功能在概念上类似,但与命令行程序grep()并不完全相同。grep

grep(expression,array)$_ >= 2在其第一个参数(例如)中运行表达式数组的每个元素(例如@F),并返回一个由结果为 true 的每个元素组成的数组。

在标量上下文中(例如与整数进行数字比较),它返回表达式为 true 的次数,而不是数组。这就是我们在这里所做的== $#F,以测试与$#F(数组中元素的数量@F)的等价性

该表达式可以是本示例中使用的简单测试,也可以是包含任何 Perl 代码的代码块。它还可以选择修改每个元素。例如,@new = grep(s/foo/bar/g, @old)将使用 @old 中已成功修改的所有元素填充 @new(即至少包含一个“foo”的 thost。所有这些元素都更改为“bar”)。perldoc -f grep详情请参阅。

相关内容