关于数学表达式:如何在bash脚本中添加数字

How can I add numbers in a bash script

我有这个bash脚本,在第16行有一个问题。我怎样才能把前面15行的结果加上它是16行中的变量吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/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


对于整数:

  • 使用算术展开:$((EXPR))

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

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

对于浮点:

bash不直接支持这一点,但是您可以使用一些外部工具:

1
2
3
4
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= 1num =2

  • bcexpr期望每个数字和运算符都是一个独立的参数,因此空格很重要。他们不能处理像3++4这样的论点。

    num=`expr $num1+ $num2`strike>


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

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

有关详细信息,请参阅http://tldp.org/ldp/abs/html/arithexp.html。


有一千零一种方法可以做到。这里有一个使用dc的:

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

但如果这对你来说太害羞(或者说便携性很重要),你可以说

1
echo $num1 $num2 + p | dc

但也许你是那种认为RPN恶心怪异的人,别担心!bc是为您而来的:

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

也就是说,你可以对你的剧本做一些不相关的改进。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/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)。

在这种情况下,解决办法是

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

num中加上可能累积的浮点数。


在巴什,

1
2
3
4
 num=5
 x=6
 (( num += x ))
 echo $num   # ==> 11

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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


我总是忘记语法,所以我来到了谷歌,但后来我再也找不到我熟悉的语法:p。这对我来说是最干净的,而且更符合我对其他语言的期望。

1
2
3
4
i=0
((i++))

echo $i;


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

1
count=$[count+1]


1
2
3
4
 #!/bin/bash
read X
read Y
echo"$(($X+$Y))"


您应该声明元为整数,然后使用算术计算

1
2
3
4
declare -i metab num
...
num+=metab
...

有关详细信息,请参阅https://www.gnu.org/software/bash/manual/html_node/shell algorithm.html shell algorithm


bash中,另一种可移植的POSIX兼容方式,可以定义为.bashrc中的函数,用于所有方便的算术运算符。

1
2
3
4
5
addNumbers () {
    local IFS='+'
    printf"%s
"
"$(( $* ))"
}

在命令行中称之为,

1
2
addNumbers 1 2 3 4 5 100
115

其思想是使用输入字段分隔符(IFS),这是bash中的一个特殊变量,用于扩展后的分词和将行拆分为单词。函数在本地更改值,以使用分词字符作为和运算符+

记住,IFS是在本地更改的,不会对超出功能范围的默认IFS行为产生影响。摘自man bash页,

The shell treats each character of IFS as a delimiter, and splits the results of the other expansions into words on these characters. If IFS is unset, or its value is exactly , the default, then sequences of , , and at the beginning and end of the results of the previous expansions are ignored, and any sequence of IFS characters not at the beginning or end serves to delimit words.

"$(( $* ))"表示由+分割的参数列表,然后使用printf函数输出和值。该函数还可以扩展为其他算术运算添加范围。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/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