我正在尝试计算一个文件中指定的给定范围内的平均值,并将其应用于不同文件中的数字。我在 bash 中找不到可以同时使用 2 个单独文件中的信息的示例。这就是我想做的:
第一个文件指定了我想要平均值的范围:
范围.txt
Sc0 1 5
Sc1 69 72
第二个文件包含我需要从中获取平均值的数字(使用第三列):
所有数字.txt
Sc0 1 30
Sc0 2 40
Sc0 3 40
Sc0 4 50
Sc0 5 10
Sc0 6 30
Sc1 69 40
Sc1 70 10
Sc1 71 20
Sc1 72 30
这就是我想要的: 平均值.txt
34
25
我试图在下面所示的 bash 循环中执行此操作,但我对 bash 脚本相当陌生,并且此代码不起作用。
#!/bin/bash
count=0;
total=0;
while read rangeName rangeStart rangeStop #make column variables for range.txt
while read name position sum #make column variables for allNumbers.txt
while [$rangeName == $name && $rangeStart < $position <= $rangeStop]; do
for i in $sum; do
total=$(echo $total+$i | bc)
((count++))
done
echo "$total / $count" | bc #print out averages
done
done < allNumbers.txt
done < ranges.txt
有人可以帮我解决这个问题吗?提前致谢。
答案1
您确实不想为此使用 shell。首先,因为它不执行浮点数学运算,因此您需要调用bc
或其他工具;第二,如您所见,因为语法非常复杂;第三,因为它是慢的。看为什么使用 shell 循环处理文本被认为是不好的做法?更多细节。
几乎任何其他语言都会更好,但这是一种使用的方法awk
:
$ awk 'NR==FNR{a[$1]["start"]=$2; a[$1]["end"]=$3; next}
{
if($2>=a[$1]["start"] && $2<=a[$1]["end"]){
values[$1]+=$3;
nums[$1]++;
}
}
END{
for(range in values){
print values[range]/nums[range]
}
}' ranges allNumbers
34
25
这与带注释的脚本相同:
#!/bin/awk -f
## If we are reading the first file
NR==FNR{
## $1 is the range name, so this will save the
## start position for this range name as a[$1]["start"] and
## the end position as a[$1]["end"]
a[$1]["start"]=$2;
a[$1]["end"]=$3;
## skip to the next line
next
}
## This will only run for the second file
{
## If this value falls in the relevant range
if($2>=a[$1]["start"] && $2<=a[$1]["end"]){
## Sum the values of this range and save
## in the values array
values[$1]+=$3;
## Count the number of values for this range and save
## in the 'nums' array.
nums[$1]++;
}
}
## After we've read both files
END{
## For each range in the 'values' array
for(range in values){
## print the average
print values[range]/nums[range]
}
}
您可以运行第一个单行代码,或者将上面的代码另存为foo.awk
,使其可执行并运行:
foo.awk ranges allNumbers