Cómo incrementar una variable en bash?

He intentado incrementar una variable numérica usando ambos var=$var+1 y var=($var+1) sin éxito. La variable es un número, aunque bash parece leerla como una cadena.

Bash versión 4.2.45 (1)-lanzamiento (x86_64-pc-linux-gnu) en Ubuntu 13.10.

Hay más de una forma de incrementar una variable en bash, pero lo que intentaste no es correcto.

Puedes usar por ejemplo expansión aritmética:

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

O puedes usar let:

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

Véase también: http://tldp.org/LDP/abs/html/dblparens.html.

var=$((var + 1))

Usos de la aritmética en bash $((...)) sintaxis.

Varias opciones para incrementar en 1 y análisis de rendimiento

Gracias a Respuesta de Radu Rădeanu eso proporciona las siguientes formas de incrementar una variable en bash:

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

También hay otras formas. Por ejemplo, mire las otras respuestas a esta pregunta.

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

Tener tantas opciones lleva a estas dos preguntas:

  1. ¿Hay alguna diferencia de rendimiento entre ellos?
  2. Si es así, ¿cuál funciona mejor?

Código de prueba de rendimiento incremental:

#!/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=100000while ((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)'donefor 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

Resultado:

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

Conclusion:

Parece que Bash es el más rápido en el rendimiento i+=1 cuando $i se declara como un entero. let las declaraciones parecen particularmente lentas, y expr es, con mucho, el más lento porque no está integrado en bash.

También está esto:

var=`expr $var + 1`

Tome nota cuidadosa de los espacios y también ` no es '

Si bien las respuestas de Radu y los comentarios son exhaustivos y muy útiles, son específicos de bash. Sé que preguntaste específicamente sobre bash, pero pensé en participar ya que encontré esta pregunta cuando estaba buscando hacer lo mismo usando sh en busybox en uClinux. Esto va más allá de bash.

Si declaras $var como un entero, entonces lo que probaste la primera vez realmente funcionará:

$ declare -i var=5$ echo $var5$ var=$var+1$ echo $var6

Referencia: Tipos de variables, Guía de Bash para Principiantes

Hay un método que falta en todas las respuestas - bc

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

bc se especifica por POSIX estándar, por lo que debería estar presente en todas las versiones de Ubuntu y sistemas compatibles con POSIX. El <<< la redirección podría modificarse para echo "$VAR" | bc para la portabilidad, pero dado que la pregunta se refiere a bash - está bien usar <<<.

El código de retorno 1 el problema está presente para todas las variantes predeterminadas (let, (()), sucesivamente.). Esto a menudo causa problemas, por ejemplo, en scripts que usan set -o errexit. Esto es lo que estoy usando para evitar el código de error 1 de expresiones matemáticas que evalúan a 0;

math() { (( "$@" )) || true; }math a = 10, b = 10math a++, b+=2math c = a + bmath mod = c % 20echo $a $b $c $mod#11 12 23 3

Esta tiene que ser la peor manera de lograr una tarea tan simple, pero supongo que solo quería documentarla por diversión (todo lo contrario de code golf).

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

o

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

En serio, utilice una de las otras opciones mucho mejores aquí.

Esta es la apuesta segura

(( var = var + 1 ))

Si el valor resultante no es cero, establecer exit en error detendrá el script

set -evar=0(( var++ ))echo You will never get here