【问题标题】:How can I find the sum of the elements of an array in Bash?如何在 Bash 中找到数组元素的总和?
【发布时间】:2012-11-18 02:06:42
【问题描述】:

我正在尝试添加由read -a 命令的用户输入定义的数组元素。我该怎么做?

【问题讨论】:

    标签: arrays bash shell unix


    【解决方案1】:
    read -a array
    tot=0
    for i in ${array[@]}; do
      let tot+=$i
    done
    echo "Total: $tot"
    

    【讨论】:

    • “让”的作用是什么?
    • 将每个项目添加到总数中。
    • 你能用 "expr" 做到这一点吗?
    • @BobbyT28,但是当 shell 有算术能力时,你不需要调用外部程序。
    • let 可以处理小数吗?我不得不使用total=$(echo "$total + $i" | bc -l)
    【解决方案2】:

    给定一个(整数)数组,这是一种添加其元素的有趣方法(在 bash 中):

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

    例如,

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

    Pro:没有循环,没有子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'应该给dc作为_42,所以:

    $ 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】:

    我的代码(我实际使用的)的灵感来自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
    

    【讨论】:

    • 优雅、快速甚至简单的解决方案。谢谢你。
    • 仅供参考,当定义 IFS 时,这可能会对脚本的其他部分产生影响
    • 是的,@MikeQ。必须将 IFS 移动到子外壳内,以防止污染正在运行的外壳。 arr=( 1 2 3 4 5 6 7 8 9 10 ); echo $(IFS='+'; bc&lt;&lt;&lt;"scale=1;(${arr[*]})/${#arr[@]}") 另外,您可以使用“Here String”而不是 echo 来保存 1 个进程。
    • @BrunoBronosky,然后可以在操作后备份和恢复 IFS 变量等..
    【解决方案4】:

    gniourf_gniourf 的 answer 非常棒,因为它不需要循环或 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"
    

    我还发现,当从双括号内调用数组时,算术扩展可以正常工作,无需读取命令:

    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"
    

    【讨论】:

      【解决方案5】:

      我喜欢简洁,所以这是我倾向于使用的:

      IFS="+";bc<<<"${array[*]}"
      

      它本质上只是列出数组的数据并将其传递给 BC 来评估它。 “IFS”是内部字段分离,它本质上指定如何分离数组,我们说用加号分隔它们,也就是说当我们将它传递给BC时,它会收到一个由加号分隔的数字列表,所以很自然它将它们加在一起。

      【讨论】:

      • 能否请您扩展&lt;&lt;&lt; simbol?
      • 回声 ${nums[@]} | sed 's/ /+/g' |公元前
      • 所以我们不使用 IFS
      【解决方案6】:

      另一个dc & bash 方法:

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

      输出:

      10.98
      

      上面运行表达式0 1 3.88 7.1 _1 + + + + pdc。注意虚拟值0,因为+s 太多了,还要注意dc 中通常的负数前缀- 必须更改为_

      【讨论】:

        【解决方案7】:
        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 的数学运算(如 this$(( "${arr[@]/%/ +} 0")))包装此字符串,它将改为返回总和

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

        1. 对于减法,只需使用 - 代替
        2. 对于乘法使用*1 而不是0

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

        1. BOOL 和示例 - 检查所有项目是否为真 (1)

          arr=(1 0 1)

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

          这将打印:否

        2. BOOL 或示例 - 检查任何项目是否为真 (1)

          arr=(1 0 0)

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

          这将打印:是的

        【讨论】:

          【解决方案8】:

          一个简单的方法

          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[@]}
          

          【讨论】:

            【解决方案9】:

            我发现使用递增变量非常简单:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-08-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-09-07
              相关资源
              最近更新 更多