Capitolo 7. Verifiche

Sommario
7.1. Costrutti condizionali
7.2. Operatori di verifica di file
7.3. Altri operatori di confronto
7.4. Costrutti condizionali if/then annidati
7.5. Test sulla conoscenza delle verifiche

Qualsiasi linguaggio di programmazione, che a ragione possa definirsi completo, deve consentire la verifica di una condizione e quindi comportarsi in base al suo risultato. Bash possiede il comando test, vari operatori parentesi quadre, parentesi rotonde e il costrutto if/then.

7.1. Costrutti condizionali

Esempio 7-1. Cos' vero?

#!/bin/bash

#  Suggerimento:
#  se non siete sicuri di come certe condizioni verranno valutate,
#+ controllatele con una verifica if.

echo

echo "Verifica \"0\""
if [ 0 ]      # zero
then
  echo "0  vero."
else
  echo "0  falso."
fi            # 0  vero.

echo

echo "Verifica \"1\""
if [ 1 ]      # uno
then
  echo "1  vero."
else
  echo "1  falso."
fi            # 1  vero.

echo

echo "Verifica \"-1\""
if [ -1 ]     # meno uno
then
  echo "-1  vero."
else
  echo "-1  falso."
fi            # -1  vero.

echo

echo "Verifica \"NULL\""
if [ ]        # NULL (condizione vuota)
then
  echo "NULL  vero."
else
  echo "NULL  falso."
fi            # NULL  falso.

echo

echo "Verifica \"xyz\""
if [ xyz ]    # stringa
then
  echo "La stringa casuale  vero."
else
  echo "La stringa casuale  falso."
fi            # La stringa casuale  vero.

echo

echo "Verifica \"\$xyz\""
if [ $xyz ]   # Verifica se $xyz  nulla, ma...
              #  solo una variabile non inizializzata.
then
  echo "La variabile non inizializzata  vero."
else
  echo "La variabile non inizializzata  falso."
fi            # La variabile non inizializzata  falso.

echo

echo "Verifica \"-n \$xyz\""
if [ -n "$xyz" ]            # Pi corretto, ma pedante.
then
  echo "La variabile non inizializzata  vero."
else
  echo "La variabile non inizializzata  falso."
fi            # La variabile non inizializzata  falso.

echo


xyz=          # Inizializzata, ma impostata a valore nullo.

echo "Verifica \"-n \$xyz\""
if [ -n "$xyz" ]
then
  echo "La variabile nulla  vero."
else
  echo "La variabile nulla  falso."
fi            # La variabile nulla  falso.


echo


# Quando "falso"  vero?

echo "Verifica \"falso\""
if [ "falso" ]              #  Sembra che "falso" sia solo una stringa.
then
  echo "\"falso\"  vero."  # e verifica se  vero.
else
  echo "\"falso\"  falso."
fi            # "falso"  vero.

echo

echo "Verifica \"\$falso\""  # Ancora variabile non inizializzata.
if [ "$falso" ]
then
  echo "\"\$falso\"  vero."
else
  echo "\"\$falso\"  falso."
fi            # "$falso"  falso.
              # Ora abbiamo ottenuto il risultato atteso.

#  Cosa sarebbe accaduto se avessimo verificato 
#+ la variabile non inizializzata "$vero"?

echo

exit 0

Esercizio. Si spieghi il comportamento del precedente Esempio 7-1.

if [ condizione-vera ]
then
   comando 1
   comando 2
   ...
else
   #  Opzionale (pu anche essere omesso).
   #  Aggiunge un determinato blocco di codice che verr eseguito se la 
   #+ condizione di verifica  falsa.
   comando 3
   comando 4
   ...
fi

Nota

Quando if e then sono sulla stessa riga occorre mettere un punto e virgola dopo l'enunciato if per indicarne il termine. Sia if che then sono parole chiave. Le parole chiave (o i comandi) iniziano gli enunciati e prima che un nuovo enunciato possa incominciare, sulla stessa riga, necessario che il precedente venga terminato.

if [ -x "$nome_file" ]; then

Else if ed elif

elif

elif la contrazione di else if. Lo scopo quello di annidare un costrutto if/then in un altro.

if [ condizione1 ]
then
   comando1
   comando2
   comando3
elif [ condizione2 ]
# Uguale a else if
then
   comando4
   comando5
else
   comando-predefinito
fi

Il costrutto if test condizione-vera l'esatto equivalente di if [ condizione-vera ]. In quest'ultimo costrutto, la parentesi quadra sinistra , [, un simbolo che invoca il comando test. La parentesi quadra destra di chiusura, ], non dovrebbe essere necessaria. Ci nonostante, le pi recenti versioni di Bash la richiedono.

Nota

Il comando test un builtin Bash che verifica i tipi di file e confronta le stringhe. Di conseguenza, in uno script Bash, test non richiama l'eseguibile esterno /usr/bin/test, che fa parte del pacchetto sh-utils. In modo analogo, [ non chiama /usr/bin/[, che un link a /usr/bin/test.

bash$ type test
test is a shell builtin
bash$ type '['
[ is a shell builtin
bash$ type '[['
[[ is a shell keyword
bash$ type ']]'
]] is a shell keyword
bash$ type ']'
bash: type: ]: not found
	      

Se, per qualche ragione, desideraste usare /usr/bin/test in uno script Bash, allora specificatene il percorso completo.

Esempio 7-2. Equivalenza di test, /usr/bin/test, [ ] e /usr/bin/[

#!/bin/bash

echo

if test -z "$1"
then
  echo "Nessun argomento da riga di comando."
else
  echo "Il primo argomento da riga di comando  $1."
fi

echo

if /usr/bin/test -z "$1"      # Stesso risultato del builtin "test".
#  ^^^^^^^^^^^^^              # Specificando il percorso completo del file.
then
  echo "Nessun argomento da riga di comando."
else
  echo "Il primo argomento da riga di comando  $1."
fi

echo

if [ -z "$1" ]                #  Funzionalit identica al precedente blocco 
                              #+ di codice.
#   if [ -z "$1"                 dovrebbe funzionare, ma...
#+  Bash risponde con il messaggio d'errore di missing close-bracket.
then
  echo "Nessun argomento da riga di comando."
else
  echo "Il primo argomento da riga di comando  $1."
fi

echo

if /usr/bin/[ -z "$1" ]       # Ancora, funzionalit identica alla precedente.
# if /usr/bin/[ -z "$1"       # Funziona, ma d un messaggio d'errore.
#                             # Nota: 
#                               Il problema  stato risolto 
#                             + nella versione Bash 3.x
then
  echo "Nessun argomento da riga di comando."
else
  echo "Il primo argomento da riga di comando  $1."
fi

echo

exit 0

Il costrutto [[ ]] la versione Bash pi versatile di [ ]. il comando di verifica esteso, adottato da ksh88.

Nota

Non pu aver luogo alcuna espansione di nome di file o divisione di parole tra [[ e ]], mentre sono consentite l'espansione di parametro e la sostituzione di comando.

file=/etc/passwd

if [[ -e $file ]]
then
  echo "Il file password esiste."
fi

Suggerimento

L'utilizzo del costrutto di verifica [[ ... ]] al posto di [ ... ] pu evitare molti errori logici negli script. Per esempio, gli operatori &&, ||, < e > funzionano correttamente in una verifica [[ ]], mentre potrebbero dare degli errori con il costrutto [ ] .

Nota

Dopo un if non sono strettamente necessari n il comando test n i costrutti parentesi quadre ( [ ] o [[ ]] ).

dir=/home/bozo

if cd "$dir" 2>/dev/null; then # "2>/dev/null" sopprime il messaggio d'errore.
  echo "Ora sei in $dir."
else
  echo "Non riesco a cambiare in $dir."
fi
Il costrutto "if COMANDO" restituisce l'exit status di COMANDO.

Per questo motivo, una condizione tra parentesi quadre pu essere utilizzata da sola, senza if, se abbinata ad un costrutto lista.

var1=20
var2=22
[ "$var1" -ne "$var2" ] && echo "$var1  diversa da $var2"

home=/home/bozo
[ -d "$home" ] || echo "La directory $home non esiste."

Il costrutto (( )) espande e valuta un'espressione aritmetica. Se il risultato della valutazione dell'espressione zero, viene restituito come exit status 1, ovvero "falso". Una valutazione diversa da zero restituisce come exit status 0, ovvero "vero". Questo in contrasto marcato con l'utilizzo di test e dei costrutti [ ] precedentemente discussi.

Esempio 7-3. Verifiche aritmetiche utilizzando (( ))

#!/bin/bash
# Verifiche aritmetiche.

# Il costrutto (( ... )) valuta e verifica le espressioni aritmetiche.
# Exit status opposto a quello fornito dal costrutto  [ ... ]!

(( 0 ))
echo "l'exit status di \"(( 0 ))\"  $?."     # 1

(( 1 ))
echo "L'exit status di \"(( 1 ))\"  $?."     # 0

(( 5 > 4 ))                                   # vero
echo "L'exit status di \"(( 5 > 4 ))\"  $?." # 0

(( 5 > 9 ))                                   # falso
echo "L'exit status di \"(( 5 > 9 ))\"  $?." # 1

(( 5 - 5 ))                                   # 0
echo "L'exit status di \"(( 5 - 5 ))\"  $?." # 1

(( 5 / 4 ))                                   # Divisione o.k.
echo "L'exit status di \"(( 5 / 4 ))\"  $?." # 0

(( 1 / 2 ))                                   # Risultato della divisione <1.
echo "L'exit status di \"(( 1 / 2 ))\"  $?." # Arrotondato a 0.
                                              # 1

(( 1 / 0 )) 2>/dev/null                       # Divisione per 0 non consentita.
#           ^^^^^^^^^^^
echo "L'exit status di \"(( 1 / 0 ))\"  $?." # 1

# Che funzione ha "2>/dev/null"?
# Cosa succederebbe se fosse tolto?
# Toglietelo, quindi rieseguite lo script.

exit 0