Guida avanzata di scripting Bash: Un'approfondita esplorazione dell'arte dello scripting di shell | ||
---|---|---|
Indietro | Avanti |
Inizializzare o cambiare il valore di una variabile
Operatore di assegnamento multiuso, utilizzato sia per gli assegnamenti aritmetici che di stringhe.
var=27 categoria=minerali # Non sono consentiti spazi né prima né dopo l'"=". |
Non bisogna confondere l'"=", operatore di assegnamento, con l'= operatore di verifica.
|
più
meno
per
diviso
elevamento a potenza
# La versione 2.02 di Bash ha introdotto l'operatore di elevamento a potenza "**". let "z=5**3" echo "z = $z" # z = 125 |
modulo, o mod (restituisce il resto di una divisione tra interi)
bash$ expr 5 % 3 2 |
Questo operatore viene utilizzato, tra l'altro, per generare numeri in un determinato intervallo (vedi Esempio 9-25, Esempio 9-28) e per impaginare l'output dei programmi (vedi Esempio 26-15 e Esempio A-6). È anche utile per generare numeri primi, (vedi Esempio A-16). Modulo si trova sorprendentemente spesso in diverse formule matematiche.
Esempio 8-1. Massimo comun divisore
#!/bin/bash # gcd.sh: massimo comun divisore # Uso dell'algoritmo di Euclide # Il "massimo comun divisore" (MCD) di due interi è l'intero #+ più grande che divide esattamente entrambi. # L'algoritmo di Euclide si basa su divisioni successive. # Ad ogni passaggio, #+ dividendo <--- divisore #+ divisore <--- resto #+ finché resto = 0. #+ Nell'ultimo passaggio MCD = dividendo. # # Per un'eccellente disamina dell'algoritmo di Euclide, vedi #+ al sito di Jim Loy, http://www.jimloy.com/number/euclids.htm. # ---------------------------------------------------------- # Verifica degli argomenti ARG=2 E_ERR_ARG=65 if [ $# -ne "$ARG" ] then echo "Utilizzo: `basename $0` primo-numero secondo-numero" exit $E_ERR_ARG fi # ---------------------------------------------------------- mcd () { dividendo=$1 # Assegnamento arbitrario. divisore=$2 #! Non ha importanza quale dei due è maggiore. # Perché? resto=1 # Se la variabile usata in un ciclo non è #+ inizializzata, il risultato è un errore #+ al primo passaggio nel ciclo. until [ "$resto" -eq 0 ] do let "resto = $dividendo % $divisore" dividendo=$divisore # Ora viene ripetuto con 2 numeri più piccoli. divisore=$resto done # Algoritmo di Euclide } # L'ultimo $dividendo è il MCD. mcd $1 $2 echo; echo "MCD di $1 e $2 = $dividendo"; echo # Esercizio : # -------- # Verificate gli argomenti da riga di comando per essere certi che siano #+ degli interi, se non lo fossero uscite dallo script con un adeguato #+ messaggio d'errore. exit 0 |
"più-uguale" (incrementa una variabile con una costante
let "var += 5" come risultato
var
è stata incrementata di
5.
"meno-uguale" (decrementa una variabile di una costante)
"per-uguale" (moltiplica una variabile per una costante)
let "var *= 4" come risultato
var
è stata moltiplicata per
4.
"diviso-uguale" (divide una variabile per una costante)
"modulo-uguale" (resto della divisione di una variabile per una costante)
Gli operatori aritmetici si trovano spesso in espressioni con expr o let.
Esempio 8-2. Utilizzo delle operazioni aritmetiche
#!/bin/bash # Contare fino a 11 in 10 modi diversi. n=1; echo -n "$n " let "n = $n + 1" # Va bene anche let "n = n + 1". echo -n "$n " : $((n = $n + 1)) # I ":" sono necessari perché altrimenti Bash tenta #+ di interpretare "$((n = $n + 1))" come un comando. echo -n "$n " (( n = n + 1 )) # Alternativa più semplice del metodo precedente. # Grazie a David Lombard per la precisazione. echo -n "$n " n=$(($n + 1)) echo -n "$n " : $[ n = $n + 1 ] # I ":" sono necessari perché altrimenti Bash tenta #+ di interpretare "$[ n = $n + 1 ]" come un comando. # Funziona anche se "n" fosse inizializzata come stringa. echo -n "$n " n=$[ $n + 1 ] # Funziona anche se "n" fosse inizializzata come stringa. #* Evitate questo costrutto perché è obsoleto e non portabile. # Grazie, Stephane Chazelas. echo -n "$n " # Ora con gli operatori di incremento in stile C. # Grazie a Frank Wang per averlo segnalato. let "n++" # anche con let "++n". echo -n "$n " (( n++ )) # anche con (( ++n ). echo -n "$n " : $(( n++ )) # anche con : $(( ++n )). echo -n "$n " : $[ n++ ] # e anche : $[ ++n ]] echo -n "$n " echo exit 0 |
In Bash, attualmente, le variabili intere sono del tipo signed long (32-bit) comprese nell'intervallo da -2147483648 a 2147483647. Un'operazione comprendente una variabile con un valore al di fuori di questi limiti dà un risultato sbagliato.
Dalla versione 2.05b, Bash supporta gli interi di 64 bit. |
Bash non contempla l'aritmetica in virgola mobile. Considera i numeri che contengono il punto decimale come stringhe.
Si utilizzi bc negli script in cui sono necessari i calcoli in virgola mobile, oppure le librerie di funzioni matematiche. |
Operatori bitwise. Gli operatori bitwise compaiono raramente negli script di shell. L'uso principale sembra essere quello di manipolare e verificare i valori letti dalle porte o dai socket. "Lo scorrimento di bit" è più importante nei linguaggi compilati, come il C e il C++, che sono abbastanza veloci per consentirne un uso proficuo.
scorrimento a sinistra (moltiplicazione per 2 per ogni posizione spostata)
"scorrimento a sinistra-uguale"
let "var <<= 2" come risultato
i bit di var
sono stati spostati di
2 posizioni verso sinistra (moltiplicazione
per 4)
scorrimento a destra (divisione per 2 per ogni posizione spostata)
"scorrimento a destra-uguale" (inverso di <<=)
AND bitwise
"AND bitwise-uguale"
OR bitwise
"OR bitwise-uguale"
complemento bitwise
NOT bitwise
XOR bitwise
"XOR bitwise-uguale"
and (logico)
if [ $condizione1 ] && [ $condizione2 ] # Uguale a: if [ $condizione1 -a $condizione2 ] # Restituisce vero se entrambe, condizione1 e condizione2, sono vere... if [[ $condizione1 && $condizione2 ]] # Funziona anche così. # Notate che l'operatore && non è consentito nel costrutto [ ... ]. |
&& può essere utilizzato, secondo il contesto, in una lista and per concatenare dei comandi. |
or (logico)
if [ $condizione1 ] || [ $condizione2 ] # Uguale a: if [ $condizione1 -o $condizione2 ] # Restituisce vero se è vera o condizione1 o condizione2 ... if [[ $condizione1 || $condizione2 ]] # Funziona anche così. # Notate che l'operatore || non è consentito nel costrutto [ ... ]. |
Bash verifica l'exit status di ogni enunciato collegato con un operatore logico. |
Esempio 8-3. Condizioni di verifica composte utilizzando && e ||
#!/bin/bash a=24 b=47 if [ "$a" -eq 24 ] && [ "$b" -eq 47 ] then echo "Verifica nr.1 eseguita con successo." else echo "Verifica nr.1 fallita." fi # ERRORE: if [ "$a" -eq 24 && "$b" -eq 47 ] #+ cerca di eseguire ' [ "$a" -eq 24 ' #+ e fallisce nella ricerca di corrispondenza di ']'. # # Nota: if [[ $a -eq 24 && $b -eq 24 ]] funziona # La verifica if con le doppie parentesi quadre è più flessibile #+ della versione con le paretesi quadre singole. # ("&&" ha un significato diverso nella riga 17 di quello della riga 6.). # Grazie a Stephane Chazelas per averlo evidenziato. if [ "$a" -eq 98 ] || [ "$b" -eq 47 ] then echo "Verifica nr.2 eseguita con successo." else echo "Verifica nr.2 fallita." fi # Le opzioni -a e -o offrono #+ una condizione di verifica composta alternativa. # Grazie a Patrick Callahan per la precisazione. if [ "$a" -eq 24 -a "$b" -eq 47 ] then echo "Verifica nr.3 eseguita con successo." else echo "Verifica nr.3 fallita." fi if [ "$a" -eq 98 -o "$b" -eq 47 ] then echo "Verifica nr.4 eseguita con successo." else echo "Verifica nr.4 fallita." fi a=rinoceronte b=coccodrillo if [ "$a" = rinoceronte ] && [ "$b" = coccodrillo ] then echo "Verifica nr.5 eseguita con successo." else echo "Verifica nr.5 fallita." fi exit 0 |
Gli operatori && e || vengono utilizzati anche nel contesto matematico.
bash$ echo $(( 1 && 2 )) $((3 && 0)) $((4 || 0)) $((0 || 0)) 1 0 1 0 |
operatore virgola
L'operatore virgola concatena due o più operazioni aritmetiche. Vengono valutate tutte le operazioni (con possibili effetti collaterali), ma viene restituita solo l'ultima.
let "t1 = ((5 + 3, 7 - 1, 15 - 4))" echo "t1 = $t1" # t1 = 11 let "t2 = ((a = 9, 15 / 3))" # Imposta "a" e calcola "t2" echo "t2 = $t2 a = $a" # t2 = 5 a = 9 |
L'operatore virgola viene impiegato principalmente nei cicli for. Vedi Esempio 10-12.