724 votos

¿Cómo incrementar una variable en bash?

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

Versión de Bash 4.2.45(1)-release (x86_64-pc-linux-gnu) en Ubuntu 13.10.

1111voto

Radu Rădeanu Puntos 62671

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

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++"

Ver también: https://tldp.org/LDP/abs/html/dblparens.html.

40 votos

O ((++variable)) o ((variable=variable+1)) o ((variable+=1)).

0 votos

O var=$(expr $var + 1)

10 votos

Curiosamente, var=0; ((var++)) devuelve un código de error mientras que var=0; ((var++)); ((var++)) no lo hace. ¿Alguna idea de por qué?

200voto

Paul Tanzini Puntos 1191
var=$((var + 1))

La aritmética en bash utiliza la sintaxis $((...)).

18 votos

Mucho mejor que la respuesta aceptada. En solo el 10% del espacio, lograste proporcionar suficientes ejemplos (uno es suficiente - nueve es excesivo hasta el punto en que simplemente estás presumiendo), y nos proporcionaste suficiente información para saber que ((...)) es la clave para usar aritmética en bash. No me di cuenta de eso solo mirando la respuesta aceptada - pensé que había un conjunto extraño de reglas sobre el orden de las operaciones o algo que llevaba a todos los paréntesis en la respuesta aceptada.

110voto

Keith Reynolds Puntos 172

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

Gracias a la respuesta de Radu Rădeanu que 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, mira en 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. ¿Existe alguna diferencia de rendimiento entre ellas?
  2. Si es así, ¿cuál es la que tiene mejor rendimiento?

Código de prueba de rendimiento incremental:

#!/bin/bash

# Para centrarnos exclusivamente en el rendimiento de cada tipo de instrucción de incremento
# deberíamos excluir la ejecución de bucles while de bash de la medición de rendimiento. Por lo tanto, vamos a cronometrar scripts individuales
# que incrementan $i a su manera única.

# Declarar i como un entero para las pruebas 12 y 13.
echo > t12 'declare -i i; i=i+1'
echo > t13 'declare -i i; i+=1'
# Configurar i para la prueba 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
    # Dado que stderr se está tuberizando a grep arriba, esto confirmará
    # que no hay errores al ejecutar el comando:
    eval "$line1"
    rm "$script"
done

Resultados:

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

Conclusión:

Al parecer, bash es más rápido al realizar i+=1 cuando $i se declara como un entero. Las declaraciones let parecen ser particularmente lentas, y expr es por mucho la más lenta porque no está integrada en bash.

0 votos

Al parecer, la velocidad se correlaciona con la longitud de los comandos. Me pregunto si los comandos llaman a las mismas funciones.

0 votos

No es lo que preguntó el OP.

3 votos

@raygozag El op preguntó cómo incrementar. Mi respuesta primero enumera muchos métodos. ¿Cómo eso no responde directamente a la pregunta del op? Luego proporciona información sobre el tiempo para cada método. Todo eso es simplemente información extra para ayudar al op a elegir qué método quiere usar.

20voto

kodiakbear Puntos 41

También está esto:

var=`expr $var + 1`

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

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

1 votos

También puedes usar i=$((i+1))

0 votos

Si la sustitución de procesos $(...) está disponible en este shell, te recomendaría usarla en su lugar.

11voto

Radon Rosborough Puntos 234

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

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

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

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X