it-swarm-eu.dev

Jak zvýšit proměnnou v bashu?

Pokusil jsem se bez úspěchu zvýšit číselnou proměnnou pomocí var=$var+1 A var=($var+1). Proměnná je číslo, ale zdá se, že bash jej čte jako řetězec.

Bash verze 4.2.45 (1) -vydání (x86_64-pc-linux-gnu) na Ubuntu 13.10.

655
user221744

Existuje více než jeden způsob, jak zvýšit proměnnou v bash, ale to, co jste vyzkoušeli, není správné.

Můžete použít například aritmetické rozšíření :

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

Nebo můžete použít let:

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

Viz také: http://tldp.org/LDP/abs/html/dblparens.html .

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

Aritmetika v bashu používá syntaxi $((...)).

169
Paul Tanzini

Různé možnosti zvýšení o 1 a analýza výkonu

Díky odpověď Radu Rădean , která poskytuje následující způsoby, jak zvýšit proměnnou v bash:

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

Existují i ​​jiné způsoby. Podívejte se například na další odpovědi na tuto otázku.

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

S tolika možností vede k těmto dvěma otázkám:

  1. Existuje mezi nimi rozdíl ve výkonu?
  2. Pokud ano, který, který vede nejlépe?

Kód testu přírůstkového výkonu:

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

Výsledek:

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

Závěr:

Zdá se, že bash je nejrychlejší při provádění i+=1 když $i je deklarováno jako celé číslo. Příkazy let se zdají být zvláště pomalé a expr je zdaleka nejpomalejší, protože není zabudován do bash.

90
Keith Reynolds

Je tu také toto:

var=`expr $var + 1`

Pečlivě si všimněte mezer a také ` není '

Zatímco odpovědi Radu a komentáře jsou vyčerpávající a velmi užitečné, jsou specifické pro bash. Vím, že jste se konkrétně zeptali na bash, ale myslel jsem, že budu doufat, protože jsem našel tuto otázku, když jsem chtěl dělat to samé pomocí sh v busyboxu pod uCLinux. Tento přenosný za bash.

18
tphelican

Pokud prohlásíte $var jako celé číslo, pak to, co jste vyzkoušeli poprvé, bude ve skutečnosti fungovat:

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

Reference: Typy proměnných, Bash Guide pro začátečníky

10
Radon Rosborough

Ve všech odpovědích chybí jedna metoda - bc

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

bc je specifikováno standardem POSIX , takže by měl být přítomen ve všech verzích systémů kompatibilních s Ubuntu a POSIX. The <<< přesměrování lze změnit na echo "$VAR" | bc pro přenositelnost, ale protože se otázka ptá na bash - je v pořádku použít <<<.

7

Pro všechny výchozí varianty (let, 1 Atd.) Je k dispozici problém s návratovým kódem (()). To často způsobuje potíže, např. Ve skriptech, které používají set -o errexit. Zde používám to, abych zabránil chybovému kódu 1 Z matematických výrazů, které vyhodnocují na 0;

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

Kecy, to bylo určeno pro jiné diskusní vlákno - nevím, jak smazat můj příspěvek

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

To musí být nejhorší způsob, jak splnit tak jednoduchý úkol, ale chtěl jsem to jen zdokumentovat pro zábavu, myslím (úplný opak oproti kódu golfu).

$ var=0
$ echo $var
0
$ var="$(python -c 'print('$var'+1)')"
$ echo $var
1

nebo

$ var="$(printf '%s\n' $var'+1' | bc)"
$ echo $var
1

Zde můžete použít jednu z dalších mnohem lepších možností.

0
leetbacoon