Le operazioni aritmetiche in Bash seguono lo stile dei linguaggi derivati da C, perciò la loro sintassi è molto simile a quella usata in C++, Java, Perl, JavaScript, C# o PHP. A differenza di questi ultimi, però, Bash supporta soltanto l'aritmetica intera, non permettendo di specificare frazioni e numeri decimali: non è possibile perciò utilizzare numeri come 3.14
(che causerebbe un errore di sintassi) e, sebbene sia permesso calcolare 7/2
, il risultato sarà quello dato dalla divisione intera (3
).
Per calcolare il risultato di un'operazione si utilizza la cosiddetta espansione aritmetica, denotata da $(())
. Ad esempio, il comando echo $((3 + 4 * (5 - 1) ))
stampa 19
.
L'espansione aritmetica supporta tutti e quattro gli operatori classici (+
, -
, *
, /
), in aggiunta all'operatore di modulo (a % b
produce il resto della divisione intera a/b
) e quello di esponenziazione (2 ** 4
risulta 16
); è possibile anche utilizzare l'operatore -
per invertire il segno di una espressione (-(3*4)
viene valutato come -12
).
All'interno di un'espressione aritmetica è possibile riferirsi a variabili dichiarate precedentemente nello stesso script senza utilizzare l'espansione di variabile (omettendo cioè il simbolo $
). Ad esempio, il codice seguente:
i = 2+3
echo $(( 7 * i ))
stampa 35
(il valore di i
viene valutato prima di effettuare la moltiplicazione, mentre scrivendo $i
verrebbe effettuata una sostituzione di stringa, producendo 7 * 2 + 3
che risulta 17
).
È possibile anche modificare il contenuto di una variabile direttamente all'interno di un'espressione aritmetica. La notazione utilizzata è molto più flessibile della tradizionale assegnazione di variabile: ad esempio, è possibile riscrivere il precedente esempio in una sola riga, come echo $(( 7 * (i = 2 + 3) ))
; in questo caso, però, anche il valore di i
viene calcolato prima di essere assegnato, perciò la variabile conterrà 5
.
In aggiunta al tradizionale operatore di assegnazione =
, Bash supporta anche operatori composti come +=
, -=
, *=
, /=
e %=
, che eseguono l'operazione seguita da un assegnamento; ad esempio, (( i *= 2 + 3 ))
è equivalente a (( i = i * (2 + 3) ))
.
Infine, Bash supporta anche l'operatore di incremento ++
e di decremento --
, che rispettivamente aggiunge o sottrae 1
dal valore della variabile che lo segue o precede; se l'operatore precede il nome della variabile, l'espressione valuta la variabile con il suo nuovo valore, mentre se l'operatore lo segue, l'espressione valuta la variabile con il suo vecchio valore. Un esempio chiarirà meglio questo concetto:
i=4
(( j = ++i ))
echo "$j $i"
i=4
(( j = i++ ))
echo "$j $i"
Un'espressione aritmetica può formare anche un comando a sé stante, usando la sintassi:
(( i = 2 + 3 ))
Questo comando imposterà $i
a 5
e ritornerà 0
come risultato ("successo" o "vero") se l'espressione verrà valutata come diversa da 0, 1
("fallimento" o "falso") nel caso in cui l'espressione risulti 0
; ciò avviene poiché in C (il linguaggio dal quale Bash prende spunto nella modellazione delle espressioni aritmetiche), 0
sta per "falso" e tutti i valori diversi da 0
(specialmente 1
) stanno per "vero".
Un altro operatore molto utile da poter utilizzare all'interno dell'operatore di espansione aritmetica è la virgola (,
), che separa diverse sotto-espressioni valutandole distintamente; il valore dell'espressione totale sarà quello dell'ultima sotto-espressione valutata. Ad esempio:
echo $(( i = 2 , j = 2 + i , i * j ))
imposta $i
a 2
, $j
a 4
e stampa 8
.
Le espressioni aritmetiche supportano anche gli operatori di confronto intero <
, >
, <=
, >=
, ==
(che sta per =
), !=
(che sta per ≠
). Ciascuno viene valutato come 1
se "vero" o 0
se "falso".
Sono supportati anche i tradizionali operatori di logica booleana !
("non" - che risulta vero solo se l'operando è falso), &&
("e" - che risulta vero solo se entrambi gli operandi sono veri), ||
("o" - che risulta vero se almeno uno degli operandi è vero). Questi ultimi due implementano la cosiddetta lazy-evaluation, non valutano cioè il secondo operando se già la valutazione del primo è sufficiente a derivare il risultato dell'operazione booleana. Ad esempio, (( ( i = 0 ) && ( j = 2 ) ))
non valuterà j = 2
(e quindi il valore di j
non verrà impostato a 2
) poiché l'operando sinistro di &&
è falso.
Infine, Bash supporta anche l'operatore condizionale c ? e1 : e2
. Questo operatore valuta innanzitutto c
; se tale espressione è vera, ritorna e1
, altrimenti, valuta e2
e ritorna il suo risultato.
Aritmetica non-intera
Come abbiamo già visto, l'aritmetica di Bash supporta solo i numeri interi. È possibile però utilizzare programmi esterni per estendere il supporto all'aritmetica non intera, includendo cioè i numeri decimali. In particolare, l'utility bc
viene spesso utilizzata per tale scopo. Il comando seguente:
echo "$(echo '3.4 + 2.2' | bc)"
stampa 5.6
. La sintassi degli operatori supportati da bc
non è totalmente diversa da quella delle espressioni aritmetiche di Bash, ma vale la pena dare un'occhiata al manuale (digitando man bc
) prima di utilizzarla nei propri script Bash.