【问题标题】:Simple math statements in bash in a for loopbash 中 for 循环中的简单数学语句
【发布时间】:2010-12-23 10:36:46
【问题描述】:

我对 bash 脚本很陌生,通常可以避免所有成本,但我需要编写一个 bash 脚本来在远程集群上执行一些简单的事情。我在执行以下操作的 for 循环时遇到问题:

for i in {1..20}
do
    for j in {1..20}
    do
        echo (i*i + j*j ) **.5  <--- Pseudo code!
    done
done

你能帮我解决这个简单的数学问题吗?我把$'s 到处乱扔,写不出来。如果您能帮助我了解如何在 bash for 循环中命名/分配变量以及 bash 数学解释的局限性(您如何计算平方根?),我将不胜感激。谢谢!

【问题讨论】:

    标签: bash math syntax for-loop


    【解决方案1】:

    使用双括号来计算变量。

    变量A=$((变量B*变量C))

    仅适用于整数。

    【讨论】:

      【解决方案2】:

      通常您会使用 $((1*3)),但您的情况将不起作用,因为 bash 不支持浮点数。您必须使用 awk、bc 或 dc 等外部工具: http://mywiki.wooledge.org/BashFAQ/022

      【讨论】:

        【解决方案3】:

        Shell 数学可以通过多种方式完成。

        echo $(( i*i + j*j ))
        echo $[ i*i + j*j ]
        expr "$i" '*' "$i" '+' "$j" '*' "$j"
        

        但是,这只能处理整数运算。相反,您可以使用bc

        echo "scale = 5; sqrt( $i*$i + $j*$j)" | bc
        

        scale 更改为所需的小数位数。

        【讨论】:

        • 您可能在 {1..20} 范围内的 1 和 20 之间缺少 ..
        • 很奇怪,它应该适用于任何 POSIX bc。如果您使用dc 会怎样?即dc -e "5 k $i $i * $j $j * + v p"
        • 呸。我缩短了 j 循环,这样它就不会淹没屏幕并引入了一个错字。
        【解决方案4】:

        算术扩展需要$((...)) 符号,所以类似于:

        echo $((i*i + j*j))
        

        但是,bash 只使用整数,因此您可能需要使用外部工具,例如 dc。

        例如

        dc -e "18k $i $i * $j $j * + v p"
        

        【讨论】:

          【解决方案5】:

          代码

          echo $[(($i * $i) + ($j * $j)) ** $X]
          

          如果$X 是一个整数,它将起作用。您正在尝试取平方根,我不确定 bash 的内置算术是否可以做到这一点。为此,您最好使用功能更强大的计算器工具(如 bc 等)。

          【讨论】:

            【解决方案6】:
            #!/bin/bash
            for i in {1..20}; do
                for j in {1..20}; do
                    echo 5k$i $i\* $j $j\*+vp | dc
                done
            done
            

            【讨论】:

            • 我的变种:printf "%s %s 10kd*rd*+vp" "$i" "$j" | dc
            【解决方案7】:

            这是一个不错的解决方案:

            for i in {1..20}
            do
               for j in {1..20}
               do
                   echo "scale = 3; sqrt($i*$i + $j*$j)" | bc
               done
            done
            

            输出将是:

            1.414
            2.236
            3.162
            2.236
            [...etc...]
            

            【讨论】:

              【解决方案8】:

              Bash 不提供数学函数。但是,您几乎可以肯定安装了 korn shell。这应该有效:

              #!/bin/ksh
              
              for i in {1..20}
              do
                  for j in {1..20}
                  do
                      x=$((sqrt(i*i + j*j)))
                      echo "sqrt($i^2 + $j^2) = $x"
                  done
              done
              

              输出的开头是

              sqrt(1^2 + 1^2) = 1.41421356237309505
              sqrt(1^2 + 2^2) = 2.2360679774997897
              sqrt(1^2 + 3^2) = 3.16227766016837933
              sqrt(1^2 + 4^2) = 4.12310562561766055
              sqrt(1^2 + 5^2) = 5.09901951359278483
              sqrt(1^2 + 6^2) = 6.08276253029821969
              sqrt(1^2 + 7^2) = 7.07106781186547524
              sqrt(1^2 + 8^2) = 8.06225774829854965
              sqrt(1^2 + 9^2) = 9.05538513813741663
              sqrt(1^2 + 10^2) = 10.0498756211208903
              

              【讨论】:

              • “几乎可以肯定”?当然不是我见过的任何 Linux 发行版的标准。也许您的意思是 *BSD?
              • ksh 在 Fedora 和 CentOS 上。
              • 它作为一个包提供,但不是默认安装的一部分。大多数 Linux 系统使用 Bash 作为默认 shell; BSD 倾向于围绕各种非 GNU shell。
              【解决方案9】:

              Bash 中另一种形式的整数数学表达式将双括号放在整个表达式的外部以进行赋值操作:

              (( var = i ** 2 ))
              (( i++ ))
              (( position += delta ))
              

              如您所见,此处不需要美元符号($(()) 内部也不需要)。此外,等号周围允许有空格。

              此外,这种形式可以用在条件句中:

              sixpacks=8             # note spaces not allowed here
              (( beerprice = 8 ))    # but you can use spaces this way
              budget=50
              
              # you can do assignments inside a conditional just like C
              until (( (( beertotal = sixpacks * beerprice )) <= budget ))
              do
                  (( sixpacks-- ))
              done
              echo "Buy ${sixpacks} six-packs at \$${beerprice} each for a total of \$${beertotal}."
              

              当然,你也可以用这个替换所有这些:

              beerprice=8
              budget=50
              
              # integer division
              (( sixpacks = budget / beerprice ))
              (( beertotal = sixpacks * beerprice ))
              echo "Buy ${sixpacks} six-packs at \$${beerprice} each for a total of \$${beertotal}."
              

              Bash 还有一个let 声明:

              let a=2**16
              let 'a>>=1'    # bitwise shift - some operations need to be quoted or escaped
              (( a>>=1 ))    # but not inside (())
              

              【讨论】:

                【解决方案10】:

                您的远程集群是否只有 bash?如果没有,试试看你有没有awk

                awk 'BEGIN{
                  for(i=1;i<=20;i++){
                    for(j=1;j<=20;j++){
                       print ( i*i + j*j ) ** 0.5
                    }
                  }
                }'
                

                【讨论】:

                  【解决方案11】:

                  使用 zsh,这将起作用

                  for i in {1..20};do
                    for j in {1..20};do
                       echo $((($i*$i + $j*$j)**.5))
                    done
                  done
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-08-19
                    • 1970-01-01
                    • 2014-05-06
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-03-17
                    • 1970-01-01
                    相关资源
                    最近更新 更多