Comment incrémenter une variable dans bash?

446

J'ai essayé d’incrémenter une variable numérique en utilisant à la fois var=$var+1 et var=($var+1) sans succès. La variable est un nombre, bien que bash semble le lire comme une chaîne.

Version de Bash 4.2.45 (1) -release (x86_64-pc-linux-gnu) sur Ubuntu 13.10.

    
posée user221744 03.12.2013 - 17:34
la source

7 réponses

707

Il y a plus d'une façon d'incrémenter une variable dans bash, mais ce que vous avez essayé n'est pas correct.

Vous pouvez par exemple utiliser expansion arithmétique :

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

Ou vous pouvez utiliser let :

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

Voir aussi: lien .

    
réponse donnée Radu Rădeanu 03.12.2013 - 17:39
la source
94
var=$((var + 1))

L'arithmétique en bash utilise la syntaxe $((...)) .

    
réponse donnée Paul Tanzini 03.12.2013 - 17:38
la source
60

Analyse des performances des différentes options

Merci à la réponse de Radu Rădeanu qui propose les méthodes suivantes pour incrémenter une variable dans bash:

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

Il y a aussi d'autres moyens. Par exemple, regardez dans les autres réponses à cette question.

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

Avoir autant d’options mène à ces deux questions:

  1. Y a-t-il une différence de performance entre eux?
  2. Si oui, lequel fonctionne le mieux?

Code de test de performance incrémentiel:

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

Résultats:

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

Conclusion:

Il semble que bash soit le plus rapide à effectuer i+=1 lorsque $i est déclaré comme un entier. Les instructions let semblent particulièrement lentes, et expr est de loin le plus lent car il ne s'agit pas d'une fonctionnalité intégrée.

    
réponse donnée wjandrea 05.10.2017 - 07:02
la source
14

Il y a aussi ceci:

var='expr $var + 1'

Notez attentivement les espaces et ' n'est pas '

Bien que les réponses de Radu et les commentaires soient exhaustifs et très utiles, ils sont spécifiques à chacun. Je sais que vous avez spécifiquement posé des questions sur bash, mais je pensais que j'y étais depuis que j'ai trouvé cette question quand je cherchais à faire la même chose en utilisant sh dans busybox sous uCLinux. Ce portable au-delà de bash.

    
réponse donnée tphelican 31.07.2015 - 19:15
la source
9

Si vous déclarez $var comme un entier, alors ce que vous avez essayé la première fois fonctionnera réellement:

$ declare -i var=5
$ echo $var
5
$ var=$var+1
$ echo $var
6

Référence: Types de variables, Bash Guide for Beginners

    
réponse donnée Radon Rosborough 23.08.2016 - 01:11
la source
6

Il manque une méthode dans toutes les réponses - bc

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

bc est spécifié par POSIX standard, il devrait donc être présent sur tous versions de systèmes compatibles Ubuntu et POSIX. La redirection de <<< pourrait être modifiée en echo "$VAR" | bc pour la portabilité, mais comme la question concerne bash - il est correct d'utiliser simplement <<< .

    
réponse donnée Sergiy Kolodyazhnyy 06.12.2015 - 23:19
la source
4

Le code retour 1 est présent pour toutes les variantes par défaut ( let , (()) , etc.). Cela provoque souvent des problèmes, par exemple dans les scripts qui utilisent set -o errexit . Voici ce que j'utilise pour empêcher le code d'erreur 1 des expressions mathématiques évaluées à 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
    
réponse donnée Juve 23.02.2017 - 14:58
la source

Lire d'autres questions sur les étiquettes