Como incrementar uma variável no bash?

425

Eu tentei incrementar uma variável numérica usando var=$var+1 e var=($var+1) sem sucesso. A variável é um número, embora bash pareça estar lendo como uma string.

Bash versão 4.2.45 (1) -release (x86_64-pc-linux-gnu) no Ubuntu 13.10.

    
por user221744 03.12.2013 / 17:34

7 respostas

674

Existe mais de uma maneira de incrementar uma variável no bash, mas o que você tentou não está correto.

Você pode usar, por exemplo, expansão aritmética :

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

Ou você pode usar let :

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

Veja também: link .

    
por Radu Rădeanu 03.12.2013 / 17:39
83
var=$((var + 1))

A aritmética no bash usa a sintaxe $((...)) .

    
por Paul Tanzini 03.12.2013 / 17:38
57

Análise de desempenho de várias opções

Graças a resposta de Radu Rădeanu que fornece as seguintes maneiras de incrementar uma variável no bash:

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

Existem outras maneiras também. Por exemplo, procure nas outras respostas sobre esta questão.

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

Ter tantas opções leva a essas duas perguntas:

  1. Existe uma diferença de desempenho entre eles?
  2. Se sim, qual o melhor desempenho?

Código de teste de desempenho 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

Conclusão:

Parece que o bash é o mais rápido em executar i+=1 quando $i é declarado como um inteiro. As declarações let parecem particularmente lentas e expr é de longe a mais lenta porque não é uma construção interna.

    
por wjandrea 05.10.2017 / 07:02
14

Também tem isto:

var='expr $var + 1'

Observe cuidadosamente os espaços e também ' não é '

Embora as respostas de Radu e os comentários sejam exaustivos e muito úteis, eles são específicos do bash. Eu sei que você especificamente perguntou sobre bash, mas eu pensei que eu cansei desde que eu encontrei esta pergunta quando eu estava olhando para fazer a mesma coisa usando sh in busybox sob uCLinux. Este portátil além do bash.

    
por tphelican 31.07.2015 / 19:15
9

Se você declarar $var como um inteiro, então o que você tentou na primeira vez funcionará:

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

Referência: Tipos de variáveis, Guia do Bash para iniciantes

    
por Radon Rosborough 23.08.2016 / 01:11
6

Existe um método em falta em todas as respostas - bc

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

bc é especificado pelo padrão POSIX , por isso deve estar presente em todos versões de sistemas compatíveis com Ubuntu e POSIX. O redirecionamento <<< pode ser alterado para echo "$VAR" | bc para portabilidade, mas como a pergunta é sobre bash , não há problema em usar apenas <<< .

    
por Sergiy Kolodyazhnyy 06.12.2015 / 23:19
3

O código de retorno 1 issue está presente para todas as variantes padrão ( let , (()) , etc.). Isso costuma causar problemas, por exemplo, em scripts que usam set -o errexit . Aqui está o que estou usando para evitar o código de erro 1 de expressões matemáticas que avaliam para 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
    
por Juve 23.02.2017 / 14:58

Tags