Question Comment incrémenter une variable dans bash?


J'ai essayé d'incrémenter une variable numérique en utilisant les deux 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 Bash version 4.2.45 (1) (x86_64-pc-linux-gnu) sur Ubuntu 13.10.


455
2017-12-03 16:34


origine




Réponses:


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 utiliser par exemple 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 également: http://tldp.org/LDP/abs/html/dblparens.html.


720
2017-12-03 16:39



ou ((++var)) ou ((var=var+1)) ou ((var+=1)). - gniourf_gniourf
ou var = $ (expr $ var + 1) - Javier López
Avec curiosité, var=0; ((var++)) renvoie un code d'erreur pendant que var=0; ((var++)); ((var++)) ne fait pas. Une idée pourquoi? - phunehehe
@phunehehe Regardez help '(('. La dernière ligne dit: Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise. - Radu Rădeanu
est-il sûr d'utiliser let var++, sans les guillemets? - wjandrea


var=$((var + 1))

Arithmétique en bash utilise $((...)) syntaxe.


101
2017-12-03 16:38



Vastement mieux que la réponse acceptée. Avec seulement 10% d’espace en plus, vous avez réussi à fournir suffisamment d’exemples (l’un est plein - neuf est excessif au point où vous ne faites que vous montrer), et vous nous avez fourni suffisamment d’informations pour savoir que ((...))est la clé de l'utilisation de l'arithmétique dans bash. Je ne me suis pas rendu compte que lorsque je regardais la réponse acceptée, je pensais qu'il y avait un ensemble de règles étranges concernant l'ordre des opérations ou quelque chose qui donnait lieu à toutes les parenthèses dans la réponse acceptée. - ArtOfWarfare


Analyse de performance des différentes options

Grâce à La réponse de Radu Rădeanu cela fournit les moyens suivants 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 d'autres moyens aussi. Par exemple, regardez les autres réponses sur 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 conduit à ces deux questions:

  1. Y a-t-il une différence de performance entre eux?
  2. Si tel est le cas, quelle est la meilleure performance?

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 ce soit plus rapide i+=1 quand $i est déclaré comme un entier. let les déclarations semblent particulièrement lentes, et expr est de loin le plus lent car ce n’est pas un


62
2017-07-31 17:15



Apparemment, la vitesse correspond à la longueur de la commande. Je me demande si les commandes appellent les mêmes fonctions. - MatthewRock
i=(expr ...) est une erreur de syntaxe. Vouliez-vous dire i=$(expr ...)? - muru
@muru corrigé, et ajouté un chèque dans la boucle for. - wjandrea


Il y a aussi ceci:

var=`expr $var + 1`

Prenez bonne note des espaces et aussi ` 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 arriverais 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.


14
2017-08-22 23:11



Vous pouvez aussi utiliser i=$((i+1)) - wjandrea
Si la substitution de processus $(...) est disponible sur ce shell, je vous recommande de l’utiliser à la place. - Radon Rosborough


Si vous déclarez $var en tant qu'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


9
2017-12-06 22:19





Il y a une méthode qui manque 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 toutes les versions des systèmes compatibles Ubuntu et POSIX. le <<< la redirection pourrait être modifiée pour echo "$VAR" | bc pour la portabilité, mais depuis la question pose sur bash - il est juste d'utiliser juste <<<.


6
2018-02-23 13:58





Le code retour 1 le problème est présent pour toutes les variantes par défaut (let, (()), etc.). Cela cause souvent des problèmes, par exemple dans les scripts qui utilisent set -o errexit. Voici ce que j'utilise pour éviter le code d'erreur 1 des expressions mathématiques qui évaluent à 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

4