Come incrementare una variabile in bash?

446

Ho cercato di incrementare una variabile numerica utilizzando sia var=$var+1 che var=($var+1) senza successo. La variabile è un numero, anche se bash sembra leggerlo come una stringa.

Bash versione 4.2.45 (1) -release (x86_64-pc-linux-gnu) su Ubuntu 13.10.

    
posta user221744 03.12.2013 - 17:34
fonte

7 risposte

711

C'è più di un modo per incrementare una variabile in bash, ma quello che hai provato non è corretto.

Puoi utilizzare ad esempio espansione aritmetica :

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

Oppure puoi utilizzare let :

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

Vedi anche: link .

    
risposta data Radu Rădeanu 03.12.2013 - 17:39
fonte
98
var=$((var + 1))

L'aritmetica in bash utilizza la sintassi $((...)) .

    
risposta data Paul Tanzini 03.12.2013 - 17:38
fonte
60

Analisi delle prestazioni di varie opzioni

Grazie alla risposta di Radu Rădeanu che fornisce i seguenti modi per incrementare una variabile in bash:

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

Ci sono anche altri modi. Ad esempio, guarda le altre risposte a questa domanda.

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

Avere così tante opzioni porta a queste due domande:

  1. C'è una differenza di prestazioni tra di loro?
  2. Se sì, quale è il migliore?

Codice di test delle prestazioni incrementali:

#!/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

Risultati:

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

Conclusione:

Sembra che bash sia il più veloce nell'eseguire i+=1 quando $i è dichiarato come numero intero. Le dichiarazioni let sembrano particolarmente lente e expr è di gran lunga la più lenta perché non è un builtin.

    
risposta data wjandrea 05.10.2017 - 07:02
fonte
14

C'è anche questo:

var='expr $var + 1'

Prendi nota degli spazi e anche ' non è '

Sebbene le risposte di Radu e i commenti siano esaustivi e molto utili, sono specifici per la bugia. So che hai fatto specificamente domande su bash, ma ho pensato che avrei fatto pipì da quando ho trovato questa domanda quando stavo cercando di fare la stessa cosa usando sh in busybox sotto uCLinux. Questo portatile oltre bash.

    
risposta data tphelican 31.07.2015 - 19:15
fonte
9

Se dichiari $var come numero intero, allora quello che hai provato la prima volta funzionerà davvero:

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

Riferimento: Tipi di variabili, Guida di Bash per principianti

    
risposta data Radon Rosborough 23.08.2016 - 01:11
fonte
6

Manca un metodo in tutte le risposte - bc

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

bc è specificato dallo standard POSIX , quindi dovrebbe essere presente su tutti versioni di sistemi compatibili con Ubuntu e POSIX. Il reindirizzamento <<< potrebbe essere modificato a echo "$VAR" | bc per la portabilità, ma poiché la domanda chiede di bash - è OK usare solo <<< .

    
risposta data Sergiy Kolodyazhnyy 06.12.2015 - 23:19
fonte
4

Il codice di ritorno 1 è presente per tutte le varianti predefinite ( let , (()) , ecc.). Ciò spesso causa problemi, ad esempio negli script che utilizzano set -o errexit . Ecco cosa sto usando per prevenire il codice di errore 1 dalle espressioni matematiche che valutano in 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
    
risposta data Juve 23.02.2017 - 14:58
fonte

Leggi altre domande sui tag