3

嗨,我有一个脚本,我用它来计算从服务器返回的一组值的标准偏差。

我可以轻松检索命令并使用该命令构建有效字符串。

bc <<< "scale=10; sqrt((0+((782636-782030)^2)+((781460-782030)^2)+((782492-782030)^2)+((781704-782030)^2)+((781860-782030)^2))/5)"

我通过遍历一个数组并将其附加到字符串中来创建这个命令。

CMD='bc <<< "scale=10; sqrt((0'
for i in "${MEMORY[@]}"; do
    CMD=$CMD'+(('$i'-'$MEAN')^2)'
done;
CMD=$CMD')/5)"'

完成此操作后,我尝试将命令字符串执行到变量中

SD=`$CMD`   
echo $SD

但是我得到了输出

File <<< is unavailable.

有任何想法吗?

4

3 回答 3

4

<<<需要由shell解析,这发生在参数扩展之前。当您尝试执行

SD=`$CMD`

中的字符串$CMD不会重新解析,因此<<<被视为文字字符串并作为参数传递给bc. 你需要类似的东西

BC_EXPRESSION='scale=10; sqrt((0'
for i in "${MEMORY[@]}"; do
    BC_EXPRESSION+="+(($i-$MEAN)^2)"
done
BC_EXPRESSION+=')/5)'

SD=$( bc <<< "$BC_EXPRESSION" )
于 2014-04-25T13:36:20.223 回答
2

您应该bc在字符串中构建命令,然后将此字符串传递给bc.

如果我理解正确,你有一个数字memory1和一个变量的数组,mean并且你想计算 的标准差memory(我猜,mean这里是 的平均值memory)。

您需要建立以下形式的字符串(X-mean)^2

sum_terms=0
for i in "${memory[@]}"; do
    sum_terms+="+(($i)-($mean))^2"
done

此时,字符串sum_terms包含扩展为类似以下内容的字符串:

0+((m1)-(mean))^2+((m2)-(mean))^2+ ... +((mn)-(mean))^2

最后,您想将其括在括号中,前置sqrt(和附加/5)并将其传递给bc

bc <<< "sqrt(($sum_terms)/5)"

一体:

sum_terms=0
for i in "${memory[@]}"; do
    sum_terms+="+(($i)-($mean))^2"
done
bc -l <<< "sqrt(($sum_terms)/5)"

请注意,我将$mean术语括在括号中,以防万一这是一个负数(否则它会与前面的负号发生冲突)——当我在这里时,我也将$i术语括在括号中。


作为旁注,您还可以使用E((X-E(X))^2)=E(X^2)-E(X)^2来计算标准偏差,并以更通用的方式进行:

给定一个数组memory,计算其标准差:

memory=( 782636 781460 782492 781704 781860 )
sum_mem=0 sum_memsq=0
for i in "${memory[@]}"; do
    sum_mem+="+($i)"
    sum_memsq+="+($i)^2"
done
mean=$(bc -l <<< "($sum_mem)/${#memory[@]}")
bc -l <<< "sqrt(($sum_memsq)/${#memory[@]}-($mean)^2)"

实际上,您在这里并不需要显式for循环,您可以printf为您完成这项工作:

memory=( 782636 781460 782492 781704 781860 )
printf -v sum_mem '+(%s)' "${memory[@]}"
printf -v sum_memsq '+(%s)^2' "${memory[@]}"
mean=$(bc -l <<< "(0$sum_mem)/${#memory[@]}")
bc -l <<< "sqrt((0$sum_memsq)/${#memory[@]}-($mean)^2)"

1让我把你所有的变量名都小写,大写的变量名被认为是不好的做法

于 2014-04-25T13:52:49.570 回答
0

请试试:

echo "scale=10; sqrt((0+((782636-782030)^2)+((781460-782030)^2)+((782492-782030)^2)+((781704-782030)^2)+((781860-782030)^2))/5)" | bc -l 

echo你的字符串和管道输出到bc -l

这将起作用

于 2014-04-25T13:33:21.707 回答