如何在Bash脚本中添加数字?


566

我有这个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

2
我认为即使使用以下答案,您也将打印零值。有一个技巧,例如进程替换,可以将最终值“ inside num”带到“ outside num”。
Scott Chu

Answers:


974

对于整数

  • 使用算术扩展$((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)。


常见陷阱

  • 设置变量时,您不能在的两边都有空格=,否则将迫使外壳程序将第一个单词解释为要运行的应用程序的名称(例如num=num

    num= 1 num =2

  • bcexpr期望将每个数字和运算符作为一个单独的参数,因此空格很重要。他们无法处理类似的参数3+ +4

    num=`expr $num1+ $num2`


1
在第一个答案它打印我EXPR:非数字参数的第二个没有工作..
尼克

1
@Nick:您是否在变量名为num1num2存在且具有整数值时尝试了此操作?
sorpigal 2011年

1
是的,它们存在,但一个变量是double ..这是一个问题吗?
尼克(Nick)

2
是的,这是个问题:)注意:$((..))算术评估是在bash中执行的。expr作为一个单独的过程执行,因此会慢很多。在不支持自动评估的系统上使用后一种(sh!= bash)
Karoly Horvath 2011年

4
由于$((…))POSIX已将其标准化,因此它变得越来越罕见expr
chepner


30

有千一百种方法可以做到这一点。这是一种用法dc(支持无限精度算术的反向抛光台式计算器):

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

但是,如果这对您来说太过麻烦了(或便携性很重要),您可以说

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


1
@Sorpigal非常感谢。.我能再问您一件事吗..我如何在末尾打印不是num而是num / 10?
尼克

23

猛烈地

 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

20

我总是忘了语法,所以我来了google,但是后来却找不到我熟悉的:P。这对我来说是最干净的,对我在其他语言中所期望的更真实。

i=0
((i++))

echo $i;


15

我也很喜欢这种方法,减少了混乱:

count=$[count+1]

1
顺便说一下,这为什么起作用?我们怎么称呼它?我找不到有关这些的文档。
skyline75489

4
不太混乱,但已弃用。
卡米尔·古德塞内


7

在中执行的另一种可移植的POSIX兼容方式bash.bashrc对于所有方便的算术运算符,都可以将其定义为功能。

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

然后在命令行中以

addNumbers 1 2 3 4 5 100
115

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

记住IFS局部改变,并没有采用默认效果IFS的功能范围之外的行为。man bash页面摘录,

外壳将IFS的每个字符视为定界符,并将其他扩展的结果拆分为这些字符上的单词。如果未设置IFS,或者其值正好是默认值,则将忽略,以及上一个扩展结果的开头和结尾处的序列,并且任何不在开头或结尾处的IFS字符序列都用于定界话。

"$(( $* ))"表示传递给被分割参数列表+和后来的总和值是使用输出printf功能。该功能可以扩展以增加其他算术运算的范围。


2
#!/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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.