其他人已经指出这expr
是仅整数,并建议在 awk 而不是 shell 中编写脚本。
您的系统上可能有许多支持任意精度数学或浮点数的工具。shell 中的两个常见计算器是bc
遵循标准的“操作顺序”,并dc
使用“反向波兰符号”。
这些中的任何一个都可以轻松地输入您的数据,从而可以生成每行平均值。例如,使用 bc:
#!/bin/sh
while read line; do
set - ${line}
c=$#
string=""
for n in $*; do
string+="${string:++}$1"
shift
done
average=$(printf 'scale=4\n(%s) / %d\n' $string $c | bc)
printf "%s // avg=%s\n" "$line" "$average"
done
当然,唯一bc
特定的部分是符号的格式和bc
倒数第三行中的本身。使用相同的基本内容dc
可能如下所示:
#!/bin/sh
while read line; do
set - ${line}
c=$#
string="0"
for n in $*; do
string+=" $1 + "
shift
done
average=$(dc -e "4k $string $c / p")
printf "%s // %s\n" "$line" "$average"
done
请注意,我的 shell 支持使用+=
. 如果您没有,您可以根据需要进行调整。
在这两个示例中,我们将输出打印到小数点后四位——用scale=4
bc 或4k
dc。我们正在处理标准输入,因此如果您将这些脚本命名为“calc”,您可以使用如下命令行运行它们:
$ ./calc < inputfile.txt
set
循环开始处的命令将变量$line
转换为位置参数,例如$1
,$2
等。然后我们处理循环中的每个位置参数for
,将所有内容附加到一个字符串中,该字符串稍后将输入计算器。
此外,你可以伪造它。
也就是说,虽然 bash 不支持浮点数,但它确实支持乘法和字符串操作。以下不使用外部工具,但似乎显示了您输入的十进制平均值。
#!/bin/bash
declare -i total
while read line; do
set - ${line}
c=$#
total=0
for n in $*; do
total+="$1"
shift
done
# Move the decimal point over prior to our division...
average=$(($total * 1000 / $c))
# Re-insert the decimal point via string manipulation
average="${average:0:$((${#average} - 3))}.${average:$((${#average} - 3))}"
printf "%s // %0.3f\n" "$line" "$average"
done
这里的重要位是: *declare
告诉 bash 将其添加到$total
而+=
不是像字符串一样附加, * 两个average=
赋值,第一个乘以$total
1000,第二个将结果拆分为千列, 和 *printf
其格式在其输出中强制执行三位小数的精度。
当然,输入仍然需要是整数。
YMMV。我并不是说这就是你应该如何解决这个问题,只是它是一种选择。:)