it-swarm.com.de

Wie inkrementiere ich eine Variable in bash?

Ich habe versucht, eine numerische Variable mit var=$var+1 und var=($var+1) zu erhöhen, ohne Erfolg. Die Variable ist eine Zahl, obwohl Bash sie als Zeichenfolge zu lesen scheint.

Bash Version 4.2.45 (1) -Release (x86_64-pc-linux-gnu) unter Ubuntu 13.10.

597
user221744

Es gibt mehr als eine Möglichkeit, eine Variable in bash zu erhöhen, aber was Sie versucht haben, ist nicht korrekt.

Sie können zum Beispiel arithmetische Erweiterung verwenden:

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

Oder Sie können let verwenden:

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

Siehe auch: http://tldp.org/LDP/abs/html/dblparens.html .

926
Radu Rădeanu
var=$((var + 1))

Die Arithmetik in Bash verwendet die Syntax $((...)).

154
Paul Tanzini

Performance-Analyse verschiedener Optionen

Dank Radu Rădeanus Antwort gibt es folgende Möglichkeiten, eine Variable in bash zu inkrementieren:

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

Es gibt auch andere Möglichkeiten. Schauen Sie sich zum Beispiel die anderen Antworten auf diese Frage an.

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

So viele Möglichkeiten zu haben, führt zu diesen beiden Fragen:

  1. Gibt es einen Leistungsunterschied zwischen ihnen?
  2. Wenn ja welche, welche schneidet am besten ab?

Inkrementeller Leistungstestcode:

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

Ergebnisse:

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

Fazit:

Es scheint, als ob Bash die schnellste Methode ist, um i+=1 auszuführen, wenn $i als Ganzzahl deklariert ist. let -Anweisungen scheinen besonders langsam zu sein, und expr ist bei weitem die langsamste, da es sich nicht um eine eingebaute Anweisung handelt.

81
Keith Reynolds

Es gibt auch Folgendes:

var=`expr $var + 1`

Beachten Sie die Leerzeichen und auch ` ist nicht '

Radus Antworten und Kommentare sind zwar erschöpfend und sehr hilfreich, aber bashspezifisch. Ich weiß, dass Sie speziell nach Bash gefragt haben, aber ich dachte, ich würde einspringen, da ich diese Frage fand, als ich das gleiche mit sh in busybox unter uCLinux tun wollte. Dieser tragbare jenseits der Bash.

18
tphelican

Wenn Sie $var als Ganzzahl deklarieren, funktioniert das, was Sie das erste Mal versucht haben:

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

Referenz: Variablentypen, Bash Guide für Anfänger

10

In allen Antworten fehlt eine Methode - bc

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

bc wird durch POSIX angegeben und sollte daher auf allen Versionen von Ubuntu- und POSIX-kompatiblen Systemen vorhanden sein. Die <<< -Umleitung kann aus Gründen der Portabilität in echo "$VAR" | bc geändert werden. Da jedoch die Frage nach bash gestellt wird, ist es in Ordnung, nur <<< zu verwenden.

7

Der Rückkehrcode 1 ist für alle Standardvarianten vorhanden (let, (()) usw.). Dies verursacht häufig Probleme, z. B. in Skripten, die set -o errexit verwenden. Hier ist, was ich verwende, um Fehlercode 1 von mathematischen Ausdrücken zu verhindern, die zu 0 ausgewertet werden.

math() { (( "[email protected]" )) || 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
6
Juve

Mist, das war für einen anderen Diskussionsthread gedacht - ich weiß nicht, wie ich meinen Beitrag löschen soll

#!/bin/bash
myname=$(basename "$0")

# parse sub options
get_opts () {
  rs='' && rc=0 # return string and return code
  while [[ $# -gt 0 ]]; do
    shift
    [[ "$1" =~ -.* ]] && break ||  rs="$rs $1" && rc=$((rc + 1))
  done
  echo "$rs"
}

# help function
help () { cat <<EOP
   $myname: -c cluster [...] -a action [...] -i instance [...]
EOP
}

while [[ $# -gt 0 ]]; do
    case $1 in
        "-a") ACTS="$(get_opts [email protected])"
           ;;
        "-i") INSTS=$(get_opts [email protected])
           ;;
        "-c") CLUSTERS=$(get_opts [email protected])
           ;;
        "-h") help
           ;;
        ?) echo "sorry, I dont do $1"
           exit
           ;;
    esac
    shift
done

exit
0
Neil Verkland