Introduzione a Unix
Indietro | Capitolo 9 Programmazione di shell | Avanti

# 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)

Indietro | Partenza | Avanti
Funzioni | Risali | Editor

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 <questions@FreeBSD.org>.
Per domande su questa documentazione, invia una e-mail a <doc@FreeBSD.org>.