我在 Ubuntu 机器上有这个数据集:
37.500 0.0000 0.005605
37.750 0.0000 -0.027858
38.000 0.0000 -0.060678
38.250 0.0000 -0.088557
38.500 0.0000 -0.109210
38.750 0.0000 -0.122482
39.000 0.0000 -0.129770
39.250 0.0000 -0.133190
39.500 0.0000 -0.134538
39.750 0.0000 -0.134015
40.000 0.0000 -0.129660
40.250 0.0000 -0.117858
40.500 0.0000 -0.094709
40.750 0.0000 -0.057622
41.000 0.0000 -0.006853
我需要找到第 3 列的最大值,该最大值位于第 1 列的 38 和 40 之间。
这只是一个示例数据集。
答案1
awk '$1 >= 38 && $1 <= 40 && $3 > max {max = $3; out = $0};
END {print out}' input.txt
注意:$3 没有正值,其中 38 <= $1 <= 40。这就是输出为空行的原因。 (为什么?因为max
默认为 0,并且没有一个负值高于该值)。
如果您想要最高值,无论是正值还是负值,请初始化max
为小于 $3 中可能的最小值的值。例如-9999
:
$ awk -v max=-9999 '$1 >= 38 && $1 <= 40 && $3 > max {max = $3; out = $0};
END {print out}' input.txt
38.000 0.0000 -0.060678
或者,使用BEGIN
块而不是-v
:
$ awk 'BEGIN {max=-9999};
$1 >= 38 && $1 <= 40 && $3 > max {max = $3; out = $0};
END {print out}' input.txt
38.000 0.0000 -0.060678
或者使用 perl,测试 $max 是否未定义,而不是将其初始化为不太可能的值:
$ perl -lane '
if ($F[0] >= 38 && $F[0] <= 40 && (!defined($max) || $F[2] > $max)) {
$max = $F[2];
$out = $_;
};
END { print $out }' input.txt
38.000 0.0000 -0.060678
答案2
秉承“一种工具完成一项任务”的 Unix 精神,一种解决方案可能是使用 过滤行awk
,然后使用 排序sort
:
awk '$1>=38 && $1<=40' test.txt | sort -n -k 3 -r | head -n 1
具体来说,我在这里使用-n
数字排序,-k3
使用第三列,-r
反转(从最大值开始),并head -n 1
显示一行。好处是它非常容易扩展到前 3 个值、最小值等。
答案3
sort
->sed
解决方案。
继续将匹配行放入保持缓冲区 ( /^(3[89]|40\.000)/h
),然后最后交换保持+模式缓冲区 ( $x
) 和打印模式缓冲区 ( $p
)。
$ sort -rk 3n test.txt |sed -nE '/^(3[89]|40\.000)/h;$x;$p'
38.000 0.0000 -0.060678
$
答案4
使用乐(以前称为 Perl_6)
~$ raku -e 'lines.map(*.words).grep(38 < *.[0] < 40).map(*.[2].Num).max.say;' file
或(扩展版本):
~$ raku -e 'my @a = lines>>.words; @a.=grep(38 < *.[0] < 40); @a.map(*.[2].Num).max.say;' file
上面的代码返回单个(最大值)值:-0.088557
基于规定的 Column_1 标准。简而言之,lines
读入,在空格分隔处断开words
,grep
并查找.[0]
38 和 40 之间的第 1 列值(零索引 = ),然后从第 3 列(零索引 = )中的固定值max
中提取该值。Num
.[2]
[感兴趣的读者请注意:当我更改 Column_1 标准以返回零行时,上面的代码告诉我max
获得的 Column_3 值是-Inf
]。
阅读评论,似乎OP也希望知道如何返回包含上述值的整行。以下代码完成该任务:
~$ raku -e 'my @a = lines>>.words; @a.=grep(38 < *.[0] < 40); put max(@a, :by(*.[2].Num));' file
38.250 0.0000 -0.088557
最后,读者可能会注意到此处获得的 Column_3 值与其他发布的答案不同。这是因为当请求针对 Column_1 值时,所使用的 Raku 代码完全按照字面意思获取 OP之间38 和 40(即大于 38 且小于 40)。请放心,将grep
上面的语句更改为 use<=
而不是<
给出 Column_3 值-0.060678
(与其他答案相同)。
输入示例:
37.500 0.0000 0.005605
37.750 0.0000 -0.027858
38.000 0.0000 -0.060678
38.250 0.0000 -0.088557
38.500 0.0000 -0.109210
38.750 0.0000 -0.122482
39.000 0.0000 -0.129770
39.250 0.0000 -0.133190
39.500 0.0000 -0.134538
39.750 0.0000 -0.134015
40.000 0.0000 -0.129660
40.250 0.0000 -0.117858
40.500 0.0000 -0.094709
40.750 0.0000 -0.057622
41.000 0.0000 -0.006853