使用 bash 取一行和文件中所有行的所有数字的平均值
Using bash to take the average of all numbers on a line and all lines in a file
本质上,我有一个几千行的txt文件,每行包含300个数字。我需要取每行 300 个数字的平均值,然后取文件中所有平均值的平均值,a la;
0.4,0.5,0.6,0.7...
0.5,0.6,0.7,0.8...
0.6,0.7,0.8,0.9...
to
0.55
0.65
0.75
to
0.65
我已经尝试了一些我在网上找到的 bash 脚本,但它们都涉及查找列的平均值,而不是整个行的平均值。我目前的策略是使用两个脚本来执行此操作,一个用于查找每行的平均值,第二个用于查找所有行的平均值,但我一直无法弄清楚任何事情。我对 bash 和 UNIX 命令还是比较陌生,所以解决方案可能很明显,但我还没有找到它。
这是你可以做的,用简单的算术和 for 循环:
#!/bin/bash
data=$(cat data.txt) # Your primary data
all=0
l=0
for i in $data; do
line=0
k=0
oldIFS=$IFS
IFS=','
for j in $i; do
line=$(echo "scale=2; ($line+$j)" | bc)
((k++))
done
IFS=$oldIFS
line=$(echo "scale=2; $line/$k" | bc)
echo "Line $l: $line"
all=$(echo "scale=2; ($all+$line)" | bc)
((l++))
done
all=$(echo "scale=2; $all/$l" | bc)
echo "Final result: $all"
结果:
Line 0: .55
Line 1: .65
Line 2: .75
Final result: .65
注意这里的IFS变量,用于改变for循环中的分隔符:https://bash.cyberciti.biz/guide/$IFS
Bash 是 shell 用于 high-level 任务,不是典型编程、读取文件和做算术的最佳选择。 awk 是此任务的标准 bash 工具。这是一个脚本:
> cat tst.awk
BEGIN { FS = "," }
{
sum = 0
for (i=1;i<=NF;i++) sum += $i
avg = sum / NF
total += avg
print "Line " NR ": " avg
}
END { print "Lines average: " total/NR }
用法和输出:
> awk -f tst.awk file
Line 1: 0.55
Line 2: 0.65
Line 3: 0.75
Lines average: 0.65
FS
是要使用的字段分隔符。 BEGIN {}
部分在读取第一行之前执行。 awk 正在逐行读取文件,并且对于每个输入行,主体 {}
都会被执行。里面的代码是 self-explanatory 并且与标准编程语言非常相似。到达文件末尾后,执行 END {}
。
本质上,我有一个几千行的txt文件,每行包含300个数字。我需要取每行 300 个数字的平均值,然后取文件中所有平均值的平均值,a la;
0.4,0.5,0.6,0.7...
0.5,0.6,0.7,0.8...
0.6,0.7,0.8,0.9...
to
0.55
0.65
0.75
to
0.65
我已经尝试了一些我在网上找到的 bash 脚本,但它们都涉及查找列的平均值,而不是整个行的平均值。我目前的策略是使用两个脚本来执行此操作,一个用于查找每行的平均值,第二个用于查找所有行的平均值,但我一直无法弄清楚任何事情。我对 bash 和 UNIX 命令还是比较陌生,所以解决方案可能很明显,但我还没有找到它。
这是你可以做的,用简单的算术和 for 循环:
#!/bin/bash
data=$(cat data.txt) # Your primary data
all=0
l=0
for i in $data; do
line=0
k=0
oldIFS=$IFS
IFS=','
for j in $i; do
line=$(echo "scale=2; ($line+$j)" | bc)
((k++))
done
IFS=$oldIFS
line=$(echo "scale=2; $line/$k" | bc)
echo "Line $l: $line"
all=$(echo "scale=2; ($all+$line)" | bc)
((l++))
done
all=$(echo "scale=2; $all/$l" | bc)
echo "Final result: $all"
结果:
Line 0: .55
Line 1: .65
Line 2: .75
Final result: .65
注意这里的IFS变量,用于改变for循环中的分隔符:https://bash.cyberciti.biz/guide/$IFS
Bash 是 shell 用于 high-level 任务,不是典型编程、读取文件和做算术的最佳选择。 awk 是此任务的标准 bash 工具。这是一个脚本:
> cat tst.awk
BEGIN { FS = "," }
{
sum = 0
for (i=1;i<=NF;i++) sum += $i
avg = sum / NF
total += avg
print "Line " NR ": " avg
}
END { print "Lines average: " total/NR }
用法和输出:
> awk -f tst.awk file
Line 1: 0.55
Line 2: 0.65
Line 3: 0.75
Lines average: 0.65
FS
是要使用的字段分隔符。 BEGIN {}
部分在读取第一行之前执行。 awk 正在逐行读取文件,并且对于每个输入行,主体 {}
都会被执行。里面的代码是 self-explanatory 并且与标准编程语言非常相似。到达文件末尾后,执行 END {}
。