我需要找到文件中每个条目的最大值和最小值:
#subset of my file
NEUTRON 20.900103
PION- 0.215176
PION- 22.716532
NEUTRON 8.043279
PION+ 1.374297
PION- 0.313350
PION+ 0.167848
当有多个条目名称时,如何循环遍历文件并找到每个名称的最小值和最大值。我已经使用 awk 来计算每个条目并且没有重复,但是每个名称的每个重复都包含一个数字,而该数字就是我试图过滤掉每个条目的最大值和最小值的数字。整个文件的 ex 输出:
Name Count Minimum Maximum
-------- ----- --------- ---------
KAON- 1 5.489958 5.489958
NEUTRON 2 8.043279 20.900103
PHOTON 10 0.034664 1.897264
PION- 5 0.192247 22.716532
PION+ 7 0.167848 7.631051
PROTON 1 1.160216 1.160216
答案1
awk '{
count[$1]++
min[$1]=(!($1 in min) || $2<min[$1]) ? $2 : min[$1]
max[$1]=(!($1 in max) || $2>max[$1]) ? $2 : max[$1]
}
END {
print "Name","Count","Minimum","Maximum"
print "----","-----","-------","-------"
for(i in count) print i,count[i],min[i],max[i]
}' file | column -t
最小数组值赋值的逻辑是:
如果第一个字段的名称在数组中不存在 ( !($1 in min)
) 或 ( ||
) 第二个字段小于当前数组值 ( $2<min[$1]
),则 ( ?
) 分配新值$2
, else( :
) 指定旧值min[$1]
。
用于| column -t
将结果漂亮地打印为表格。如果您不需要它,可以将其删除。
输出:
Name Count Minimum Maximum
---- ----- ------- -------
PION+ 2 0.167848 1.374297
PION- 3 0.215176 22.716532
NEUTRON 2 8.043279 20.900103
答案2
正如 Jeff Schaller 所指出的,bash 不是一个文本处理器,尽管您所要求的实现并不是特别困难。所以这里有一种方法可以做到这一点......无论它的价值如何。
$ awk '!/^#.*/ {
((++cnt[$1]));
if (cnt[$1]==1)
{min[$1]=max[$1]=$2}
else if ($2 < min[$1])
{ min[$1]=$2}
else if ($2 > max[$1])
{max[$1]=$2}
}
END {
printf "%-10s%7s%10s%12s\n","Name","Count","Minimum", "Maximum";
for (i in cnt)
printf "%-10s%7d%10.6g%12.8g\n", i,cnt[i],min[i],max[i];
}' testdata
输出:
Name Count Minimum Maximum
PION+ 2 0.167848 1.374297
PION- 3 0.215176 22.716532
NEUTRON 2 8.04328 20.900103
解释:
- 跳过以 a 开头的任何行(记录)
#
awk
对于每个记录,在程序执行开始时从 0 开始将 cnt[$1] 加 1- 如果当前记录的第一个字段值“$1”以前从未见过,则将该值的最小值和最大值初始化为值“$2”。
- 在其他情况下(当在之前的记录中至少看到一次值“$1”时),更新最小值和最大值
- 最后使用格式化打印以尊重 OP 中示例输出的方面。