Vraag Hoe een variabele verhogen in bash?


Ik heb geprobeerd om een ​​numerieke variabele te verhogen met beide var=$var+1 en var=($var+1) zonder succes. De variabele is een getal, hoewel bash het als een tekenreeks lijkt te lezen.

Bash-versie 4.2.45 (1) -release (x86_64-pc-linux-gnu) op Ubuntu 13.10.


455
2017-12-03 16:34


oorsprong




antwoorden:


Er is meer dan één manier om een ​​variabele in bash te verhogen, maar wat je hebt geprobeerd is niet correct.

U kunt bijvoorbeeld gebruiken rekenkundige uitbreiding:

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

Of je kunt gebruiken let:

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

Zie ook: http://tldp.org/LDP/abs/html/dblparens.html.


720
2017-12-03 16:39



of ((++var)) of ((var=var+1)) of ((var+=1)). - gniourf_gniourf
of var = $ (expr $ var + 1) - Javier López
Vreemd, var=0; ((var++)) geeft een foutcode terug terwijl var=0; ((var++)); ((var++)) doet niet. Enig idee waarom? - phunehehe
@phunehehe Kijk naar help '(('. De laatste regel zegt: Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise. - Radu Rădeanu
is het veilig om te gebruiken let var++, zonder de aanhalingstekens? - wjandrea


var=$((var + 1))

Rekenen in bash-gebruik $((...)) syntaxis.


101
2017-12-03 16:38



Veel beter dan het geaccepteerde antwoord. In slechts 10% zoveel ruimte wist je genoeg voorbeelden te geven (er is er genoeg - negen is overkill tot het moment dat je net begint te pronken), en je hebt ons genoeg informatie gegeven om dat te weten ((...))is de sleutel tot het gebruik van rekenkunde in bash. Ik wist niet dat ik alleen maar naar het geaccepteerde antwoord keek - ik dacht dat er een rare set regels was over de volgorde van operaties of iets dat leidde tot alle haakjes in het geaccepteerde antwoord. - ArtOfWarfare


Prestatieanalyse van verschillende opties

Dankzij Het antwoord van Radu Rădeanu die de volgende manieren biedt om een ​​variabele in bash te verhogen:

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

Er zijn ook andere manieren. Kijk bijvoorbeeld in de andere antwoorden op deze vraag.

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

Met zoveel opties leidt tot deze twee vragen:

  1. Is er een verschil in prestaties tussen beide?
  2. Zo ja, wat presteert het best?

Incrementele prestatietestcode:

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

resultaten:

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

Conclusie:

Het lijkt erop dat bash het snelst presteert i+=1 wanneer $i wordt gedeclareerd als een geheel getal. let verklaringen lijken bijzonder traag, en expr is verreweg de langzaamste omdat het niet is ingebouwd.


62
2017-07-31 17:15



Blijkbaar correleert snelheid met opdrachtlengte. Ik vraag me af of de commando's dezelfde functies oproepen. - MatthewRock
i=(expr ...) is een syntaxisfout. Bedoelde je i=$(expr ...)? - muru
@muru opgelost en een controle in de for-lus toegevoegd. - wjandrea


Er is ook dit:

var=`expr $var + 1`

Let goed op de spaties en ook ` is niet '

Hoewel Radu's antwoorden, en de opmerkingen, uitputtend en zeer nuttig zijn, zijn ze bash-specifiek. Ik weet dat je specifiek naar bash hebt gevraagd, maar ik dacht dat ik het zou inluiden sinds ik deze vraag vond toen ik op zoek was om hetzelfde te doen met sh in busybox onder uCLinux. Deze draagbare verder dan bash.


14
2017-08-22 23:11



Je kan ook gebruiken i=$((i+1)) - wjandrea
Als procesvervanging $(...) is beschikbaar op deze schaal. Ik raad u aan deze te gebruiken. - Radon Rosborough


Als u verklaart $var als een geheel getal, dan zal wat je de eerste keer hebt geprobeerd echt werken:

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

Referentie: Typen variabelen, Basishandleiding voor beginners


9
2017-12-06 22:19





Er ontbreekt één methode in alle antwoorden - bc

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

bc wordt opgegeven door POSIX standaard, dus moet aanwezig zijn in alle versies van Ubuntu en POSIX-compatibele systemen. De <<< omleiding kan worden gewijzigd echo "$VAR" | bc voor draagbaarheid, maar sinds de vraag ernaar vraagt bash - het is OK om het gewoon te gebruiken <<<.


6
2018-02-23 13:58





De retourcode 1 probleem is aanwezig voor alle standaardvarianten (let, (()), enz.). Dit veroorzaakt vaak problemen, bijvoorbeeld in scripts die gebruiken set -o errexit. Dit is wat ik gebruik om foutcode te voorkomen 1 van wiskundige uitdrukkingen die evalueren naar 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

4