如何增加bash中的变量?


608

我试图同时使用var=$var+1var=($var+1)不成功地增加一个数字变量。该变量是一个数字,尽管bash似乎正在以字符串形式读取它。

在Ubuntu 13.10上的Bash版本4.2.45(1)-发行版(x86_64-pc-linux-gnu)。

Answers:


946

在bash中增加变量的方法有多种,但是您尝试的方法不正确。

您可以使用例如算术扩展

var=$((var+1))
((var=var+1))
((var+=1))
((var++))

或者您可以使用let

let "var=var+1"
let "var+=1"
let "var++"

另请参阅:http : //tldp.org/LDP/abs/html/dblparens.html


31
((++var))((var=var+1))((var+=1))
gniourf_gniourf 2013年

6
奇怪的是,var=0; ((var++))返回错误代码,而var=0; ((var++)); ((var++))没有返回。知道为什么吗?
phunehehe

15
@phunehehe看看help '(('。最后一行说:Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise.
RaduRădeanu2014年

2
我怀疑评估为零,1这就是@gniourf_gniourf的提示为何包含((++var))但不包含的原因((var++))
DreadPirateShawn 2014年

4
使用安全let var++,没有引号吗?
wjandrea

160
var=$((var + 1))

bash中的算术使用$((...))语法。


9
比公认的答案好得多。在仅10%的空间中,您设法提供了足够的示例(一个很好,其中9个在您炫耀时就显得有些过高了),并且您向我们提供了足够的信息,这((...))是使用算术的关键猛扑 我没有意识到仅仅查看接受的答案-我认为关于操作顺序或导致接受的答案中所有括号的规则有一套怪异的规则。
ArtOfWarfare

82

各种选项的性能分析

感谢RaduRădeanu的回答,它提供了以下增加bash中变量的方法:

var=$((var+1))
((var=var+1))
((var+=1))
((var++))
let "var=var+1"
let "var+=1" 
let "var++"

还有其他方法。例如,查看有关此问题的其他答案。

let var++
var=$((var++))
((++var))
{
    declare -i var
    var=var+1
    var+=1
}
{
    i=0
    i=$(expr $i + 1)
}

有这么多的选择会导致以下两个问题:

  1. 它们之间在性能上有区别吗?
  2. 如果是这样,哪个表现最好?

增量性能测试代码:

#!/bin/bash

# To focus exclusively on the performance of each type of increment
# statement, we should exclude bash performing while loops from the
# performance measure. So, let's time individual scripts that
# increment $i in their own unique way.

# Declare i as an integer for tests 12 and 13.
echo > t12 'declare -i i; i=i+1'
echo > t13 'declare -i i; i+=1'
# Set i for test 14.
echo > t14 'i=0; i=$(expr $i + 1)'

x=100000
while ((x--)); do
    echo >> t0 'i=$((i+1))'
    echo >> t1 'i=$((i++))'
    echo >> t2 '((i=i+1))'
    echo >> t3 '((i+=1))'
    echo >> t4 '((i++))'
    echo >> t5 '((++i))'
    echo >> t6 'let "i=i+1"'
    echo >> t7 'let "i+=1"'
    echo >> t8 'let "i++"'
    echo >> t9 'let i=i+1'
    echo >> t10 'let i+=1'
    echo >> t11 'let i++'
    echo >> t12 'i=i+1'
    echo >> t13 'i+=1'
    echo >> t14 'i=$(expr $i + 1)'
done

for script in t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14; do
    line1="$(head -1 "$script")"
    printf "%-24s" "$line1"
    { time bash "$script"; } |& grep user
    # Since stderr is being piped to grep above, this will confirm
    # there are no errors from running the command:
    eval "$line1"
    rm "$script"
done

结果:

i=$((i+1))              user    0m0.992s
i=$((i++))              user    0m0.964s
((i=i+1))               user    0m0.760s
((i+=1))                user    0m0.700s
((i++))                 user    0m0.644s
((++i))                 user    0m0.556s
let "i=i+1"             user    0m1.116s
let "i+=1"              user    0m1.100s
let "i++"               user    0m1.008s
let i=i+1               user    0m0.952s
let i+=1                user    0m1.040s
let i++                 user    0m0.820s
declare -i i; i=i+1     user    0m0.528s
declare -i i; i+=1      user    0m0.492s
i=0; i=$(expr $i + 1)   user    0m5.464s

结论:

声明为整数i+=1时,bash似乎执行最快$ilet语句似乎特别慢,并且expr由于它不是内置函数,因此迄今为止最慢。


显然,速度与命令长度相关。我不知道这些命令是否调用相同的功能。
MatthewRock

18

还有这个:

var=`expr $var + 1`

请注意空格,并且`不是'

尽管Radu的答案和评论非常详尽且很有帮助,但它们都是针对bash的。我知道您确实曾问过有关bash的问题,但是我想加入,因为当我想在uCLinux下的busybox中使用sh进行相同的操作时发现了这个问题。这种便携式超越bash。


1
您也可以使用i=$((i+1))
wjandrea

如果$(...)在此shell上可以进行进程替换,则建议改用它。
拉登·罗斯伯勒


7

所有答案中都缺少一种方法- bc

$ VAR=7    
$ bc <<< "$VAR+2"
9
$ echo $VAR
7
$ VAR=$( bc <<< "$VAR+1" )
$ echo $VAR
8

bc是由POSIX标准指定的,因此应该在所有版本的Ubuntu和POSIX兼容系统中都存在。该<<<重定向可以被改变,以echo "$VAR" | bc便携性,但因为这个问题询问bash-这是确定只使用<<<


6

返回代码1出现问题的所有默认变种(let(()),等)。这通常会引起麻烦,例如,在使用的脚本中set -o errexit。这是我用来防止错误代码出现1在数学表达式中的结果0

math() { (( "$@" )) || true; }

math a = 10, b = 10
math a++, b+=2
math c = a + b
math mod = c % 20
echo $a $b $c $mod
#11 12 23 3

0

这必须是完成这种简单任务的最糟糕的方法,但我只是想以有趣的方式对其进行记录(与代码高尔夫完全相反)。

$ var=0
$ echo $var
0
$ var="$(python -c 'print('$var'+1)')"
$ echo $var
1

要么

$ var="$(printf '%s\n' $var'+1' | bc)"
$ echo $var
1

在这里认真使用其他更好的选择之一。

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.