9.9 Comandi di controllo

9.9.1 Condizionale if

L'espressione condizionale if è disponibile in entrambe le shell, ma con una diversa sintassi.

9.9.1.1 Sh

if condizione1
then
        lista di comandi se condizione1 è vera (true)
[elif condizione2
        then lista di comandi se condizione2 è vera (true)]
[else
        lista di comandi se condizione1 è falsa (false)]
fi

Le condizioni sono sottoposte usualmente al comando test(1) o [] (Vedere la sezione 9.9.6). L'if e then devono essere separati con un newline o un punto e virgola (;).

#!/bin/sh
if [ $# -ge 2 ]
then
  echo $2
elif [ $# -eq 1 ]; then
  echo $1
else
  echo Nessun input
fi

Sono richiesti degli spazi nel formato della condizione di test(1), uno dopo [ e uno prima di ]. Questo script potrebbe comportarsi in modo differente a seconda che ci siano zero, uno o più argomenti su linea di comando. Iniziando con nessun argomento:

$ ./if.sh
Nessun input

Ora con un argomento:

$ ./if.sh one
one

E ora con due argomenti:

$ ./if.sh one two
two

9.9.1.2 Csh

if (condizione) comando
   -oppure-
if (condizione1) then
        lista di comandi se condizione1 è vera (true)
[else if (condizione2) then
        lista di comandi se condizione2 è vera (true)]
[else
        lista di comandi se condizione1 è falsa (false)]
endif

L'if e then devono stare sulla stessa linea.

#!/bin/csh -f
if ( $#argv >= 2 ) then
  echo $2
else if ( $#argv == 1 ) then
  echo $1
else
  echo Nessun input
endif

Di nuovo, questo script potrebbe comportarsi in modo differente a seconda che ci siano zero, uno o più argomenti su linea di comando. Iniziando con nessun argomento:

% ./if.csh
Nessun input

Ora con un argomento:

% ./if.csh one
one

E ora con due argomenti:

% ./if.csh one two
two

9.9.2 Condizionale switch e case

Per scegliere tra una serie di valori di tipo stringa relativi a un parametro si usa case nella shell Bourne e switch nella shell C.

9.9.2.1 Sh

case parametro in
        schema1[|schema1a]) lista1 di comandi;;
        schema2) lista2 di comandi
                 lista2a di comandi;;
        schema3) lista3 di comandi;;
        *) ;;
esac

Si possono usare validi nomi di file meta-caratteri all'interno dello schema per il confronto. I ;; concludono ogni scelta e possono essere sulla stessa linea della scelta o a seguito di un newline, dopo l'ultimo comando per la scelta. Schemi alternativi per la scelta di un particolare caso sono separati da una barra verticale |, come nel primo schema dell'esempio precedente. I simboli wild card ,? per indicare un generico carattere e * per far corrispondere alcuni caratteri, possono essere usati singolarmente o in modo adiacente per completare stringhe.

Questo semplice esempio illustra come usare l'espressione condizionale case.

#!/bin/sh
case $1 in
        aa|ab) echo A
        ;;
        b?)    echo "B \c"
               echo $1;;
        c*)    echo C;;
        *)     echo D;;
esac

Quindi quando si esegue lo script con l'argomento posto sulla colonna di sinistra, lo script risponde come sulla colonna di destra:

aa A
ab A
ac D
bb B bb
bbb D
c C
cc C
fff D

9.9.2.2 Csh

switch (parametro)
case schema1:
        lista1 di comandi
        [breaksw]
case schema2:
        lista2 di comandi
        [breaksw]
default:
        lista di comandi per il comportamento di default
        [breaksw]
endsw

breaksw è opzionale e può essere usato per interrompere lo switch dopo che si è verificata una corrispondenza del valore di tipo stringa del parametro confrontato. Switch non accetta | nella lista degli schemi, ma permette di unire insieme diverse strutture case per fornire un simile risultato. Il seguente script di shell C ha lo stesso comportamento dell'esempio precedente, riferito al case della shell Bourne.

#!/bin/csh -f
switch ($1)
        case aa:
        case ab:
                echo A
                breaksw
        case b?:
                echo -n "B "
                echo $1
                breaksw
        case c*:
                echo C
                breaksw
        default:
                echo D
endsw

9.9.3 for e foreach

Per effettuare un ciclo tra una lista di valori di tipo stringa si possono usare i comandi for e foreach.

9.9.3.1 Sh

for variabile [in lista_di_valori]
do
        lista di comandi
done

La lista_di_valori è opzionale, presupponendo $@ se nulla viene specificato. Ogni valore in questa lista viene sostituito sequenzialmente in variabile fino a quando la lista risulta vuota. Possono essere usati wild card, che vengono applicati ai nomi dei file nella directory corrente. Di seguito si illustra il ciclo for che copia tutti i file che finiscono con .old negli stessi nomi che finiscono però con .new. In questi esempi l'utility basename(1) estrae la parte base del nome affinchè si possa modificarne l'estensione.

#!/bin/sh
for file in *.old
do
        newf=`basename $file .old`
        cp $file $newf.new
done

9.9.3.2 Csh

foreach variabile (lista_di_valori)
        lista di comandi
end

L'equivalente script in shell C per copiare tutti i file con estensione .old negli stessi file con estensione .new è:

#!/bin/csh -f
foreach file (*.old)
        set newf = `basename $file .old`
        cp $file $newf.new
end

9.9.4 while

Il comando while permette di effettuare il ciclo sempre che la condizione sia vera.

9.9.4.1 Sh

while condizione
do
        lista di comandi
        [break]
        [continue]
done

Un semplice script per illustrare il ciclo while è:

#!/bin/sh
while [ $# -gt 0 ]
do
        echo $1
        shift
done

Questo script prende la lista degli argomenti, ne visualizza il primo, quindi effettua uno shift nella lista verso sinistra, perdendo il primo elemento originale. Il ciclo viene ripetuto fino a quando tutti gli argomenti sono stati spostati fuori dalla lista.

$ ./while.sh one two three
one
two
three

9.9.4.2 Csh

while (condizione)
        lista di comandi
        [break]
        [continue]
end

Se si vuole che la condizione sia sempre vera si specifica 1 all'interno del test condizionale.

Lo script di shell C equivalente a quello precedente è:

#!/bin/csh -f
while ($#argv != 0 )
        echo $argv[1]
        shift
end

9.9.5 until

Questo costrutto di ciclo è solamente disponibile per la shell Bourne.

until condizione
do
        lista di comandi se la condizione è falsa
done

La condizione viene verificata all'inizio di ogni ciclo e il ciclo termina quando la condizione è vera.

Uno script equivalente all'esempio del while precedente è:

#!/bin/sh
until [ $# -le 0 ]
do
        echo $1
        shift
done

Si noti che qui si verifica per minore o uguale, piuttosto che per maggiore, poichè il ciclo until viene abilitato da una condizione falsa.

Sia il ciclo until che il while sono solamente eseguiti se la condizione è soddisfatta. La condizione viene valutata prima dell'esecuzione dei comandi.

9.9.6 test

Le espressioni condizionali vengono valutate per valori veri o falsi. Questo, di solito, viene realizzato con test(1) o equivalentemente con i suoi operatori []. Se la condizione viene valutata vera, viene settato uno stato di uscita zero (TRUE), altrimenti viene settato uno stato di uscita non-zero (FALSE). Se non ci sono argomenti viene settato uno stato di uscita non-zero. Gli operatori utilizzati nelle espressioni condizionali della shell Bourne sono mostrati qui sotto.

Per i nomi di file le opzioni per test(1) sono date con la sintassi seguente:

-opzione filename

Le opzioni di test(1) disponibili per i file includono:

-r vero se il file esiste ed è leggibile
-w vero se il file esiste ed è scrivibile
-x vero se il file esiste ed è eseguibile
-f vero se il file esiste ed è un file regolare (o per csh(1) esiste e non è una directory)
-d vero se il file esiste ed è una directory
-h o -L vero se il file esiste ed è un link simbolico
-c vero se il file esiste ed è un file speciale a caratteri (ad esempio un dispositivo al quale si accede un carattere alla volta)
-b vero se il file esiste ed è un file speciale a blocchi (ad esempio un dispositivo al quale si accede in blocchi di dati)
-p vero se il file esiste ed è un file pipe (fifo)
-u vero se il file esiste ed è setuid (ad esempio ha il bit set-user-id settato a s o S nel terzo bit)
-g vero se il file esiste ed è setgid (ad esempio ha il bit set-group-id settato a s o S nel sesto bit)
-k vero se il file esiste e ha lo sticky bit settato (una t nel nono bit)
-s vero se il file esiste ed ha una dimensione maggiore di zero

C'è un test per i descrittori di file:

-t [descrittore_file] vero se l'aperto descrittore del file specificato (1, stdout(4), di default) è associato ad un terminale

Ci sono test per le stringhe:

-z stringa vero se la lunghezza della stringa è zero
-n stringa vero se la lunghezza della stringa non è zero
stringa1 = stringa2 vero se stringa1 è identica a stringa2
stringa1 != stringa2 vero se stringa1 non è identica a stringa2
stringa vero se la stringa non è nulla

Ci sono dei confronti per gli interi:

n1 -eq n2 vero se gli interi n1 e n2 sono uguali
n1 -ne n2 vero se gli interi n1 e n2 non sono uguali
n1 -gt n2 vero se l'intero n1 è maggiore dell'intero n2
n1 -ge n2 vero se l'intero n1 è maggiore o uguale dell'intero n2
n1 -lt n2 vero se l'intero n1 è minore dell'intero n2
n1 -le n2 vero se l'intero n1 è minore o uguale dell'intero n2

Sono disponibili i seguenti operatori logici:

! negazione (unaria)
-a and (binario)
-o or (binario)
() le espressioni all'interno di ( ) vengono raggruppate insieme. Può essere necessario quotare le parentesi ( ) per impedire alla shell di interpretarle.

9.9.7 Operatori relazionali e logici della shell C

La shell C possiede un suo set di operatori logici e relazionali built-in. In ordine decrescente di priorità questi sono:

(...) raggruppa espressioni con ( )
~ inverso (il suo complemento)
! negazione logica
*, /, % moltiplicazione, divisione, modulo
+, - addizione, sottrazione
<<, >> shift a sinistra di bit, shift a destra di bit
<= minore o uguale
>= maggiore o uguale
< minore
> maggiore
= = uguale
!= non uguale
=~ uguale a stringa
!~ non uguale a stringa
& AND bit
^ XOR bit (or esclusivo)
| OR bit
&& AND logico
|| OR logico
{comando} vero (1) se il comando termina con uno stato di uscita 0, falso (0) altrimenti.

Inoltre la shell C permette richieste sul tipo e sui permessi dei file con gli operatori seguenti:

-r ritorna vero (1) se il file esiste ed è leggibile, altrimenti ritorna falso (0)
-w vero se il file esiste ed è scrivibile
-x vero se il file esiste ed è eseguibile
-f vero se il file esiste e non è una directory
-d vero se il file esiste ed è una directory
-e vero se il file esiste
-o vero se l'utente corrente è il proprietario del file
-z vero se il file ha una lunghezza zero (file vuoto)

Questo, ed altri documenti, possono essere scaricati da ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

Per domande su FreeBSD, leggi la documentazione prima di contattare <[email protected]>.
Per domande su questa documentazione, invia una e-mail a <[email protected]>.