¿Cómo incrementar una variable en bash?

454

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

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

    
pregunta user221744 03.12.2013 - 17:34

7 respuestas

719

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

Puede usar, por ejemplo, expansión aritmética :

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

O puede usar let :

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

Ver también: enlace .

    
respondido por el Radu Rădeanu 03.12.2013 - 17:39
99
var=$((var + 1))

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

    
respondido por el Paul Tanzini 03.12.2013 - 17:38
62

Análisis de rendimiento de varias opciones

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, mire las otras respuestas sobre esta pregunta.

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

Tener tantas opciones conduce a estas dos preguntas:

  1. ¿Hay una 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=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

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:

Parece que bash es el más rápido en la realización de i+=1 cuando $i se declara como un entero. Las sentencias let parecen particularmente lentas, y expr es de lejos la más lenta porque no es una instrucción incorporada.

    
respondido por el wjandrea 05.10.2017 - 07:02
14

También hay esto:

var='expr $var + 1'

Tome nota 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 conectar desde que encontré esta pregunta cuando estaba buscando hacer lo mismo usando sh en busybox bajo uCLinux. Este portátil más allá de bash.

    
respondido por el tphelican 31.07.2015 - 19:15
9

Si declara $var como un entero, entonces lo que probó la primera vez realmente funcionará:

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

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

    
respondido por el Radon Rosborough 23.08.2016 - 01:11
6

Falta un método en todas las respuestas - bc

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

bc está especificado por POSIX estándar, por lo que debe estar presente en todos versiones de Ubuntu y sistemas compatibles con POSIX. La redirección <<< podría modificarse a echo "$VAR" | bc para la portabilidad, pero como la pregunta es sobre bash , está bien usar <<< .

    
respondido por el Sergiy Kolodyazhnyy 06.12.2015 - 23:19
4

El código de retorno 1 está presente para todas las variantes predeterminadas ( let , (()) , etc.). 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 = 10
math a++, b+=2
math c = a + b
math mod = c % 20
echo $a $b $c $mod
#11 12 23 3
    
respondido por el Juve 23.02.2017 - 14:58

Lea otras preguntas en las etiquetas