674

我有这个 Bash 脚本,我在第 16 行遇到了问题。如何获取第 15 行的先前结果并将其添加到第 16 行的变量中?

#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do
    for j in `ls output-$i-*`; do
        echo "$j"

        metab=$(cat $j|grep EndBuffer|awk '{sum+=$2} END { print sum/120}') (line15)
        num= $num + $metab   (line16)
    done
    echo "$num"
 done
4

12 回答 12

1156

对于整数

  • 使用算术扩展$((EXPR))

    num=$((num1 + num2))
    num=$(($num1 + $num2))       # Also works
    num=$((num1 + 2 + 3))        # ...
    num=$[num1+num2]             # Old, deprecated arithmetic expression syntax
    
  • 使用外部expr实用程序。请注意,这仅适用于真正的旧系统。

    num=`expr $num1 + $num2`     # Whitespace for expr is important
    

对于浮点

Bash 不直接支持这一点,但您可以使用几个外部工具:

num=$(awk "BEGIN {print $num1+$num2; exit}")
num=$(python -c "print $num1+$num2")
num=$(perl -e "print $num1+$num2")
num=$(echo $num1 + $num2 | bc)   # Whitespace for echo is important

您还可以使用科学记数法(例如,2.5e+2)。


常见的陷阱

  • 设置变量时,两边不能有空格=,否则会强制 shell 将第一个单词解释为要运行的应用程序的名称(例如,num=num

    num= 1 num =2

  • bcexpr期望每个数字和运算符作为单独的参数,因此空格很重要。他们不能处理像3+ +4.

    num=`expr $num1+ $num2`

于 2011-06-14T19:28:34.250 回答
167

使用$(( ))算术扩展。

num=$(( $num + $metab ))

有关详细信息,请参阅第 13 章算术展开

于 2011-06-14T19:28:41.113 回答
33

有一千零一种方法可以做到这一点。这是一个使用dc(支持无限精度算术的逆波兰桌面计算器):

dc <<<"$num1 $num2 + p"

但是,如果这对您来说太 bash-y(或可移植性问题),您可以说

echo $num1 $num2 + p | dc

但也许你是那些认为 RPN 令人讨厌和奇怪的人之一;不用担心!bc在这里为您服务:

bc <<< "$num1 + $num2"
echo $num1 + $num2 | bc

也就是说,您可以对脚本进行一些不相关的改进:

#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do
    for j in output-$i-* ; do # 'for' can glob directly, no need to ls
            echo "$j"

             # 'grep' can read files, no need to use 'cat'
            metab=$(grep EndBuffer "$j" | awk '{sum+=$2} END { print sum/120}')
            num=$(( $num + $metab ))
    done
    echo "$num"
done

Bash FAQ 022中所述,Bash 本身并不支持浮点数。如果您需要对浮点数求和,则需要使用外部工具(如bcdc)。

在这种情况下,解决方案是

num=$(dc <<<"$num $metab + p")

将累积的可能浮点数添加到num.

于 2011-06-14T20:17:54.117 回答
25

在巴什,

 num=5
 x=6
 (( num += x ))
 echo $num   # ==> 11

请注意,Bash 只能处理整数运算,因此如果您的 AWK 命令返回一个分数,那么您需要重新设计:这是您的代码重写了一点,以便在 AWK 中进行所有数学运算。

num=0
for ((i=1; i<=2; i++)); do
    for j in output-$i-*; do
        echo "$j"
        num=$(
           awk -v n="$num" '
               /EndBuffer/ {sum += $2}
               END {print n + (sum/120)}
           ' "$j"
        )
    done
    echo "$num"
done
于 2011-06-14T22:32:23.320 回答
24

我总是忘记语法,所以我来谷歌搜索,但后来我找不到我熟悉的那个:P。这对我来说是最干净的,也更符合我对其他语言的期望。

i=0
((i++))

echo $i;
于 2013-10-28T20:42:18.733 回答
20

我也很喜欢这种方法。杂乱无章:

count=$[count+1]
于 2013-10-25T09:22:55.533 回答
18
 #!/bin/bash
read X
read Y
echo "$(($X+$Y))"
于 2016-09-29T21:06:27.453 回答
10

您应该将metab声明为整数,然后使用算术评估

declare -i metab num
...
num+=metab
...

有关详细信息,请参阅6.5 壳算术

于 2017-04-30T09:34:32.353 回答
10

使用 shell 内置let. 它类似于(( expr ))

A=1
B=1
let "C = $A + $B"
echo $C # C == 2

来源:Bash let 内置命令

于 2020-04-26T21:18:31.517 回答
7

在 Bash 中执行的另一种可移植的POSIX兼容方式,可以将其定义为.bashrc方便所有算术运算符的函数。

addNumbers () {
    local IFS='+'
    printf "%s\n" "$(( $* ))"
}

只需在命令行中调用它,

addNumbers 1 2 3 4 5 100
115

这个想法是使用Input-Field-Separator(IFS),这是 Bash 中的一个特殊变量,用于扩展后的分词并将行拆分为单词。该函数在本地更改值以使用分词字符作为求和运算符+

请记住IFS是在本地更改的,并且不会IFS函数范围之外的默认行为生效。man bash该页面的摘录,

Shell 将 IFS 的每个字符视为分隔符,并将其他扩展的结果拆分为这些字符上的单词。如果 IFS 未设置,或者它的值恰好是默认值,则忽略前面扩展结果的开头和结尾处的 , 和字。

"$(( $* ))"表示传递给拆分的参数列表,然后+使用该printf函数输出总和值。该函数还可以扩展以增加其他算术运算的范围。

于 2017-01-14T15:40:44.200 回答
4
#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do      
    for j in `ls output-$i-*`; do
        echo "$j"

        metab=$(cat $j|grep EndBuffer|awk '{sum+=$2} END { print sum/120}') (line15)
        let num=num+metab (line 16)
    done
    echo "$num"
done
于 2018-03-20T04:11:30.003 回答
0
#!/usr/bin/bash

#integer numbers
#===============#

num1=30
num2=5

echo $(( num1 + num2 ))
echo $(( num1-num2 ))
echo $(( num1*num2 ))
echo $(( num1/num2 ))
echo $(( num1%num2 ))

read -p "Enter first number : " a
read -p "Enter second number : " b
# we can store the result
result=$(( a+b ))
echo sum of $a \& $b is $result # \ is used to espace &


#decimal numbers
#bash only support integers so we have to delegate to a tool such as bc
#==============#

num2=3.4
num1=534.3

echo $num1+$num2 | bc
echo $num1-$num2 | bc
echo $num1*$num2 |bc
echo "scale=20;$num1/$num2" | bc
echo $num1%$num2 | bc

# we can store the result
#result=$( ( echo $num1+$num2 ) | bc )
result=$( echo $num1+$num2 | bc )
echo result is $result

##Bonus##
#Calling built in methods of bc 

num=27

echo "scale=2;sqrt($num)" | bc -l # bc provides support for calculating square root

echo "scale=2;$num^3" | bc -l # calculate power
于 2022-01-08T08:59:00.183 回答