Costrutti di Test

Stato di ritorno dei comandi

Ogni comando ritorna alla shell chiamante un numero intero, lo stato di ritorno, di valore:

  • 0 - se il comando ha avuto successo
  • >0 - se il comando è fallito

Lo stato di ritorno dell'ultimo comando eseguito è contenuto nella variabile $?

Esempio:

ls /etc/passwd
/etc/passwd
echo $?
0
ls /etc/password
… no such …
echo $?
2

Costrutto if

La sintassi è:

if comando
then
  istruzioni
else
  istruzioni
fi

Notare che l'argomento di if non è una codizione logica booleana, come in altri linguaggi, ma un comando.

if esegue il comando e ne testa lo stato di ritorno

  • Se ha avuto successo compie le istruzioni dopo il then
  • Se è fallito compie le istruzioni dopo lo else
  • La branca else è opzionale
  • E' terminato da fi

L'indentazione non è necessaria, ma è raccomandata per chiarezza visiva

Esempio.

(if1.sh)

#! /bin/bash
if ls $1 > /dev/null 2>&1
then
  echo "Il file $1 esiste"
else
  echo "il file $1 non esiste"
fi

Provare con vari test:

./if1.sh if1.sh
Il file if1.sh esiste
./if1.sh zippo
il file zippo non esiste
./if1.sh if*
Il file if1.sh esiste

Note

> /dev/null ridirige lo standard output sul device nullo, scarta l'output del comando

2>&1 ridirige lo standard error in merge con lo standard output, scarta gli errori del comando

Nel caso di ./if1.sh if* la shell espande il carattere jolly * prima dell'esecuzione del comando
Se vi sono più file soddisfatti dal carattere jolly, solo il primo
viene mostrato.

Notare il caso limite:

./if1.sh 
Il file  esiste

Occorre testare che vi siano argomenti prima di eseguire il resto della procedura

Il comando test

if esegue un comando

  • Normalmente gli if hanno una condizione logica

Il comando test ha come argomenti un'espressione logica

  • test ha successo se la condizione è vera
  • fallisce se la condizione è falsa

Tramite test si può far provare a if una condizione logica

Rivisitazione dell'esempio precedente:

(if2.sh)

#! /bin/bash
if test $# -eq 0
then
  echo "$0: usage: $0 file" 1>&2
  exit 1
fi
if ls $1 > /dev/null 2>&1
then
  echo "Il file $1 esiste"
else
  echo "il file $1 non esiste"
fi

Notare la filosofia: se qualcuno degli ingredienti necessari alla procedura non è presente, allora si termina subito con un messaggio d'errore.

Il comando exit 1 esce dalla procedura e ritorna lo stato di ritorno 1 alla shell chiamante.

In altre parole: non speriamo di avere tutto per poter continuare a lavorare; speriamo che qualcosa manchi così non si deve lavorare.

Oltre che

if test cond_logica

si può scrivere

if [ cond_logica ]

Notare gli spazi obbligatori vicino alle quadre.

Questo è cosiddetto zucchero sintattico per rendere l'aspetto più simile a sintassi tradizionale. Quello che succede internamente è che [ è un alias del comando test.

Esempio.

(test1.sh)

#! /bin/bash
echo -n "Dammi un numero: "
read num
if test $num -gt 5
then
  echo "Il numero e' maggiore di cinque"
else
  echo "E' un numero piccolo"
fi

Operatori di test

Operatori di paragone numerico:

  • -gt - maggiore
  • -ge - maggiore o uguale
  • -lt - minore
  • -le - minore o uguale
  • -eq - uguale
  • -ne - non uguale

Operatori di paragone tra stringhe:

  • "str1" = "str2" - uguali
  • "str1" != "str2" - diverse

Esempio.

(test2.sh)

#! /bin/bash
if [ "$(whoami)" = "root" ]
then
  echo "Attenzione: sei l'amministratore"
else
  echo "Non sei l'amministratore"
fi

Altro esempio, basato sul fatto che la variabile d'ambiente $UID contiene lo User Id, e che se questo è 0 abbiamo i poteri del supruser, ossia dell'amministratore.

(test3.sh)

#! /bin/bash
warn=Attenzione:
non=Non
if [ $UID -eq 0 ]
then
  unset non
else
  unset warn
fi
echo "$warn $non sei l'amministratore"

Il comando unset seguito dal nome di una variabile, toglie quella variabile se esiste, e non da errore se non esiste.

Serve per assicurarsi che una variabile non sia settata.

La stampa di una variabile non settat aproduce uno spazio vuoto (non la stringa nulla).

Altre opzioni di test

Il comando test serve anche a testare le proprietà di un file:

  • -e file - esiste
  • -f file - esiste ed è un file regolare
  • -d file - esiste ed è una directory
  • -L file - esiste ed è un link simbolico
  • -r file - esiste ed ha il permesso di lettura
  • -w file - esiste ed ha il permesso di scrittura
  • -x file - esiste ed ha il permesso di esecuzione
  • -u file - esiste ed è un SUID
  • -g file - esiste ed è uno SGID
  • -k file - esiste ed ha il POSIX bit
  • -s file - esiste e ha dimensione maggiore di zero
  • -b file - esiste ed è un device a blocchi
  • -c file - esiste ed è un device a caratteri
  • -p file - esiste ed è una pipe
  • -S file - esiste ed è un socket

I permesi sono intesi per l'utente che sta eseguendo la procedura corrente.

E ancora:

  • -O file - siamo i possessori del file
  • -G file - il file è del nostro gruppo
  • file1 -nt file2 - file1 è più nuovo di file2 (modifica)
  • file1 -ot file2 - file1 è più vecchio di file2
  • file1 -ef file2 - file1 e file2 sono link diretti allo stesso inode

Più test diversi si possono unire con operatori logici:

  • ! - NOT
  • -a - AND
  • -o - OR

Anche test di stringhe:

  • -z $var - testa se var è una stringa vuota
  • -n $var testa se var è una stringa non vuota

Nel test di una stringa con if
il costrutto:

if [ "$str1" = "" ]

causa errore. Meglio scivere:

if [ "x$str1" = "x" ]

oppure meglio ancora:

if [ -z "$str1" ]

Il Costrutto case

Sintassi:

case variabile in
    cost1 )
        istruzioni 
        istruzioni ;;
    cost2 | cost3 )
        istruzioni ;;
    . . .
    * )
        istruzioni ;;
esac

case confronta la variabile con ogni costante

Al primo match esegue le istruzioni che seguono fino al ;; poi esce dopo esac (si, è case a rovescio, cos' come fi è if arovescio)

La costante * è sempre soddisfatta
e se c'è deve essere l'ultima della lista

Esempio.

(case1.sh)

#! /bin/bash
cat << EOF
       Unix e':
1) Un bellissimo sistema operativo
2) Un'agenzia ONU
3) Un club di bagni turchi

EOF
echo -n "Scelta? "
read sc
case $sc in
    1 )
      echo "Bravo!"
      echo "Hai studiato" ;;
    2|3 )
      echo "No!" ;;
    *)
      echo "Scelta non prevista" ;;
esac

Note

2|3 denota un OR

Piccola miglioria, il comando interno read è più complesso di quanto si creda (RTFM: help read).
Sostituire le linee:

echo -n "Scelta? "
read sc

con la linea

read -sn 1 -p "Scelta? " sc

ove:

  • -s - silenzioso
  • -n 1 - legge solo un carattere
  • -p "..." - pronto

results matching ""

    No results matching ""