A Bash tud aritmetikát végezni, de csak egész számokkal. Ha lebegőpontos számításra van szükséged, külső programot kell hívnod (például awk vagy bc).
Az aritmetikai operátorok (precedencia szerinti sorrendben) a kézikönyvben vannak felsorolva: Shell Arithmetic.
Emellett a Bash csak bizonyos helyeken végez aritmetikát (ezeket aritmetikai „kontextusoknak” nevezzük).
Az aritmetikai kifejtés a parancsbehelyettesítéshez hasonlít, csak dupla zárójelekkel.
$(( expression ))
Ez a szintaxis a kifejezés kiértékelésének eredményét állítja elő. Gyakran használjuk arra, hogy az eredményt egy változóban rögzítsük:
x=$(( 3 + 4 ))
A zárójeleken belüli szóközök mennyisége rajtad múlik. Ez a stílus és az olvashatóság kérdése.
x=$(( 3 + 4 ))
y=$((5+6))
A kedves szerző szívesen tesz be szóközöket, hogy az aritmetikai kifejezés jobban látható legyen a zárójeleken belül.
Az aritmetikai feltételt dupla zárójelek között hajtjuk végre, a kezdő $ nélkül:
(( expression ))
Ez nem az eredményt állítja elő. Ehelyett egy kilépési állapotot állít elő.
A (( belsejében a Bash ugyanazt az igaz/hamis értelmezést használja, mint a C nyelv: a nulla hamis, a nem nulla igaz.
Ez pont az ellenkezője annak, ahogy a Bash a kilépési állapotokat értékeli!
Ezt a szintaxist általában két helyen használjuk:
egy if utasítás vagy egy while ciklus COMMAND részeként.
if (( x == y - 1 )); then ...
while (( y > 0 )); do ...
önálló parancsként egy változó értékének módosítására.
(( x = x + 1 ))
echo "new value for x is $x"
Légy óvatos, ha így használod az aritmetikát set -e mellett.
Ha a kifejezés nullára értékelődik ki, a kilépési állapot nem nulla lesz, és a Bash leáll.
x=0
(( x++ ))
echo "you will see this"
set -e
x=0
(( x++ ))
echo "shell exits on the previous line; you won't see this"
A ++ operátorról szóló részletesebb fejtegetésért lásd ezt a cikket: Postincrement vs Preincrement
Van még néhány más hely, ami aritmetikai kontextus:
for (( i = 0; i < 10; i++ )); do
echo "$i"
done
Egy számokkal indexelt tömb indexrésze.
echo "The next element is ${array[x + 1]}"
# ................................^^^^^
A tömbökről bővebben a Tömbök fogalomdokumentumban olvashatsz.
A ${var:offset:length} kifejtés eltolás és hossz részei.
(( expression )) előnyben részesítendő a let "expresson" helyett.
Az aritmetikai feltétel szerkezettel ellentétben a let kifejezés ki van téve a fájlnév-kifejtésnek és a szófelbontásnak, és idézőjeleket igényel.Változóértékadás, amikor a változónak „egész attribútuma” van.
# variable x does not have the integer attribute
x="3 + 4"
declare -p x # => declare -- x="3 + 4"
# variable y has the integer attribute
declare -i y
y="4 + 5"
declare -p y # => declare -i y="9"
A szerző véleménye szerint a declare -i használata korlátozott.
Legfőbb előnye, hogy lehetővé teszi a „csupasz” aritmetikát (az aritmetikai kifejezés szintaxisa nélkül).
Ez zavart okozhat a kódod olvasóinak, mert az aritmetikai kifejezések váratlan helyeken értékelődnek ki.
Íme az aritmetikai kontextusok egyik szempontja, amely javítja az olvashatóságot.
height=10
width=20
area=$(( height * width ))
Észrevetted, hogy a $ dollárjelek hiányoznak a változók elől az aritmetikai kifejezésben?
A Bash megengedi ezt.
Ez sokkal könnyebben olvashatóvá teszi a kifejezéseket.
A kézikönyv ezt írja,
Egy kifejezésen belül a shell-változókra név szerint is hivatkozhatsz anélkül, hogy a paraméter-kifejtés szintaxist használnád.
Még a tömb elemeknél is működik:
point1=(10 15) # these are (x, y) coordinates
point2=(20 7)
distance_squared=$(( (point1[0] - point2[0])**2 + (point1[1] - point2[1])**2 ))
De más paraméterkifejezéseknek a saját speciális szintaxisukat kell használniuk. Például egy string hosszának megkétszerezése:
s="hello world"
len=$(( ${#s} * 2 ))
Ugyanez vonatkozik a pozíciós paraméterekre is. Ha az első két pozíciós paraméter a szélességet és a magasságot jelöli:
area=$(( $1 * $2 ))