如何在Bash中找到数组元素的总和?

20

我正在尝试添加由用户输入定义的数组元素,这是通过 read -a 命令完成的。我该如何实现?

9个回答

32
read -a array
tot=0
for i in ${array[@]}; do
  let tot+=$i
done
echo "Total: $tot"

"let" 的作用是什么? - BobbyT28
1
将每个项目添加到总数。 - perreal
你能用“expr”来完成这个吗? - BobbyT28
@BobbyT28,但是当shell具有执行算术运算的能力时,您不需要调用外部程序。 - glenn jackman
let 命令可以用于小数吗?我不得不使用 total=$(echo "$total + $i" | bc -l) - userABC123

25

给定一个整数数组,这里有一种有趣的方法在bash中添加它的元素:

sum=$(IFS=+; echo "$((${array[*]}))")
echo "Sum=$sum"

e.g.,

$ array=( 1337 -13 -666 -208 -408 )
$ sum=$(IFS=+; echo "$((${array[*]}))")
$ echo "$sum"
42

优点:无循环,无子shell!

缺点:仅适用于整数

编辑(2012/12/26)。

由于此帖被推上来了,我想与您分享另一种有趣的方法,使用 dc,这样就不仅限于整数了:

$ dc <<< '[+]sa[z2!>az2!>b]sb1 2 3 4 5 6 6 5 4 3 2 1lbxp'
42

这条神奇的代码可以将所有数字相加。很整洁,是吧?
如果您的数字存储在一个数组array中:
$ array=( 1 2 3 4 5 6 6 5 4 3 2 1 )
$ dc <<< '[+]sa[z2!>az2!>b]sb'"${array[*]}lbxp"
42

实际上,负数有一个小技巧。 数字“-42”应该作为“_42”交给dc,因此:
$ array=( -1.75 -2.75 -3.75 -4.75 -5.75 -6.75 -7.75 -8.75 )
$ dc <<< '[+]sa[z2!>az2!>b]sb'"${array[*]//-/_}lbxp"
-42.00

可以。

优点:可处理浮点数。

缺点:使用外部进程(但如果想进行非整数算术,则没有选择,不过dc可能是最轻量级的工具)。


3
那个超出了我的理解范围 :-| - BobbyT28
不适用于自然数:$ echo "${arrr []}" 2 1 34 3 2 $ IFS=+ read <<< "${arrr []}" 然后没有提供 + :$ echo $REPLY 2 1 34 3 2 - Chris
第一个(非常聪明的)解决方案会创建一个子shell,因为Bash中的命令替换($(...))总是会创建一个子shell。请参见mklement0的答案以及当命令替换比孤立的相同命令产生更多子shell时发生了什么? - pjh

9

我的代码(我实际使用的)灵感来自于 gniourf_gniourf 的回答。我个人认为这更加易读易懂并且便于修改。它还可以接受浮点数,而不仅仅是整数。

对数组中的值求和:

arr=( 1 2 3 4 5 6 7 8 9 10 )
IFS='+' sum=$(echo "scale=1;${arr[*]}"|bc)
echo $sum # 55

通过小的改动,您可以获得值的平均数:

arr=( 1 2 3 4 5 6 7 8 9 10 )
IFS='+' avg=$(echo "scale=1;(${arr[*]})/${#arr[@]}"|bc)
echo $avg # 5.5

一种优雅、快速甚至简单的解决方案。谢谢。 - Sopalajo de Arrierez
1
请注意,当定义IFS时,这可能会对脚本的其他部分产生影响。 - Mike Q
1
是的,@MikeQ。IFS必须移动到子shell中以防止污染正在运行的shell。arr =(1 2 3 4 5 6 7 8 9 10); echo $(IFS ='+'; bc<<<“scale = 1;($ {arr [*] })/ $ {# arr [@]}”)此外,您可以使用“Here String”而不是echo来保存1个进程。 - Bruno Bronosky
1
@BrunoBronosky,那么在操作后可以备份和恢复IFS变量等。 - Mike Q
1
@MikeQ 在这里重新定义IFS的方式只会对单个命令行生效。在这里不需要备份和恢复IFS。 - SpinUp __ A Davis

7

gniourf_gniourf的答案非常好,因为它不需要循环或bc。对于任何对实际例子感兴趣的人,这里是一个函数,它从/proc/cpuinfo读取所有CPU核心的总数,而不会影响IFS:

# Insert each processor core count integer into array
cpuarray=($(grep cores /proc/cpuinfo | awk '{print $4}'))
# Read from the array and replace the delimiter with "+"
# also insert 0 on the end of the array so the syntax is correct and not ending on a "+"
read <<< "${cpuarray[@]/%/+}0"
# Add the integers together and assign output to $corecount variable
corecount="$((REPLY))"
# Echo total core count
echo "Total cores: $corecount"

我还发现,当从双括号中调用数组时,算术扩展可以正常工作,无需使用read命令:
cpuarray=($(grep cores /proc/cpuinfo | awk '{print $4}'))
corecount="$((${cpuarray[@]/%/+}0))"
echo "Total cores: $corecount"

通用:

array=( 1 2 3 4 5 )
sum="$((${array[@]/%/+}0))"
echo "Total: $sum"

6
我喜欢简洁明了的风格,这是我通常使用的写法:
IFS="+";bc<<<"${array[*]}"

它基本上只列出数组的数据并将其传递给评估它的BC。 "IFS"是内部字段分隔符,它实际上指定如何分隔数组,我们说要使用加号分隔它们,这意味着当我们将其传递到BC时,它会接收由加号分隔的数字列表,因此自然地将它们加在一起。


请问您能详细解释一下 <<< 符号的用法吗? - Sopalajo de Arrierez
1
echo ${nums[@]} | sed 's/ /+/g' | bc - Dave Thomas
所以我们不要搞乱IFS。 - Dave Thomas

3

另一种 dcbash 方法:

arr=(1 3.88 7.1 -1)
dc -e "0 ${arr[*]/-/_} ${arr[*]/*/+} p"

输出:

10.98

上述代码使用 dc 运行表达式 0 1 3.88 7.1 _1 + + + + p。请注意,由于有一个多余的 +,所以需要添加虚拟值 0,同时也要注意在 dc 中通常的负数前缀 - 必须改为 _

2
arr=(1 2 3) //or use `read` to fill the array
echo Sum of array elements: $(( ${arr[@]/%/ +} 0))
Sum of array elements: 6

解释:

  1. "${arr[@]/%/ +}" 将返回 1 + 2 + 3 +
  2. 在末尾添加额外的零,我们将得到 1 + 2 + 3 + 0
  3. 通过将这个字符串包装在BASH的数学运算中,像这样 $(( "${arr[@]/%/ +} 0")),它将返回总和

这可以用于其他数学运算。

  1. 要进行减法,只需使用 -
  2. 要进行乘法,使用 *1 代替 0

也可以与逻辑运算符一起使用。

  1. 布尔AND示例-检查所有项是否为true(1)

    arr=(1 0 1)

    if [[ $((${arr[@]/%/ &} 1)) -eq 1 ]]; then echo "yes"; else echo "no"; fi

    这将打印: no

  2. 布尔OR示例-检查任何项是否为true(1)

    arr=(1 0 0)

    if [[ $((${arr[@]/%/ |} 0)) -eq 1 ]]; then echo "yes"; else echo "no"; fi

    这将打印: yes


0

我觉得使用一个递增变量非常简单:

result2=0
for i  in ${lineCoffset[@]};
do
    result2=$((result2+i))  
done
echo $result2

0

一种简单的方法

function arraySum 
{
        sum=0
        for i in ${a[@]};
        do
              sum=`expr $sum + $i`  
        done
        echo $sum
}

a=(7 2 3 9)
echo -n "Sum is = " 
arraySum ${a[@]}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接