Capitolo 25. Costrutti lista

I costrutti "lista and" e "lista or" rappresentano un mezzo per elaborare consecutivamente un elenco di comandi. I costrutti lista possono sostituire efficacemente complessi enunciati if/then annidati nonché l'enunciato case.

Concatenare comandi

lista and

comando-1 && comando-2 && comando-3 && ... comando-n
Ogni comando che a turno deve essere eseguito si accerta che quello precedente abbia restituito come valore di ritorno true (zero). Alla prima restituzione di false (non-zero), la serie dei comandi termina (il primo comando che ha restituito false è l'ultimo che è stato eseguito).

Esempio 25-1. Usare una lista and per verificare gli argomenti da riga di comando

#!/bin/bash
# "lista and"

if [ ! -z "$1" ] && echo "Argomento nr.1 = $1" && [ ! -z "$2" ] &&\
echo "Argomento nr.2 = $2"
                   
then
  echo "Allo script sono stati passati almeno 2 argomenti."
  # Tutti i comandi della serie hanno restituito true.
else
  echo "Allo script sono stati passati meno di 2 argomenti."
  # Almeno uno dei comandi ha restituito false.
fi
# Notate che "if [ ! -z $1 ]" funziona, ma il suo supposto equivalente,
#  if [ -n $1 ] no. 
#    Comunque, l'uso del quoting risolve il problema.
#  if [ -n "$1" ] funziona.  
#    State attenti!
# In una verifica, è sempre meglio usare le variabili con il QUOTING.


# Questo svolge la stesso compito usando solamente enunciati if/then.
if [ ! -z "$1" ]
then
  echo "Argomento nr.1 = $1"
fi
if [ ! -z "$2" ]
then
  echo "Argomento nr.2 = $2"
  echo "Allo script sono stati passati almeno 2 argomenti."
else
  echo "Allo script sono stati passati meno di 2 argomenti."
fi
# È più lungo e meno elegante di una "lista and".


exit 0

Esempio 25-2. Un'altra verifica di argomenti da riga di comando utilizzando una lista and

#!/bin/bash

ARG=1         # Numero degli argomenti attesi.
E_ERR_ARG=65  # Valore d'uscita se il numero di argomenti passati è errato.

test $# -ne $ARG && echo "Utilizzo: `basename $0` $ARG \
argomento/i" && exit $E_ERR_ARG
#  Se la prima condizione dà come risultato vero (numero errato di argomenti 
#+ passati allo script), allora vengono eseguiti i comandi successivi
#+ e lo script termina.

# La riga seguente verrà eseguita solo se fallisce la verifica precedente.
echo "Allo script è stato passato un numero corretto di argomenti."

exit 0

#  Per verificare il valore d'uscita, eseguite "echo $?" dopo che lo script 
#+ è terminato.

Naturalmente, una lista and può anche essere usata per impostare le variabili ad un valore predefinito.

arg1=$@ && [ -z "$arg1" ] && arg1=DEFAULT    
		     
	      #  Imposta $arg1 agli argomenti passati da riga di comando,
              #+ se ce ne sono.
              #  Ma . . .  la impostata a DEFAULT se, da riga di comando, non è
              #+ stato passato niente.

lista or

comando-1 || comando-2 || comando-3 || ... comando-n
Ogni comando che a turno deve essere eseguito si accerta che quello precedente abbia restituito false. Alla prima restituzione di true, la serie dei comandi termina (il primo comando che ha restituito true è l'ultimo che è stato eseguito). Ovviamente è l'inverso della "lista and".

Esempio 25-3. Utilizzare la lista or in combinazione con una lista and

#!/bin/bash

#  delete.sh, utility di cancellazione di file non molto intelligente.
#  Utilizzo: delete nomefile

E_ERR_ARG=65

if [ -z "$1" ]
then
  echo "Utilizzo: `basename $0` nomefile"
  exit $E_ERR_ARG  # Nessun argomento? Abbandono.
else
  file=$1          # Imposta il nome del file.
fi


[ ! -f "$file" ] && echo "File \"$file\" non trovato. \
Mi rifiuto, in modo vile, di cancellare un file inesistente."
#  LISTA AND, fornisce il messaggio d'errore se il file non è presente.
#  Notate il messaggio di echo che continua alla riga successiva per mezzo del
#+ carattere di escape.

[ ! -f "$file" ] || (rm -f $file; echo "File \"$file\" cancellato.")
# LISTA OR, per cancellare il file se presente.

# Notate l'inversione logica precedente.
# La LISTA AND viene eseguita se il risultato è true, la LISTA OR se è false.

exit 0

Attenzione

Se il primo comando di una "lista or" restituisce true, esso verrà eseguito comunque .

# ==> Questi frammenti di codice, presi dallo script/etc/rc.d/init.d/single
#+==> di Miquel van Smoorenburg, illustrano l'impiego delle liste "and" e "or".
# ==> I commenti con la "freccia" sono stati aggiunti dall'autore del libro.

[ -x /usr/bin/clear ] && /usr/bin/clear
  # ==> Se /usr/bin/clear esiste, allora viene invocato.
  # ==> Verificare l'esistenza di un comando prima che venga eseguito
  #+==> evita messaggi d'errore e i conseguenti avvertimenti.

  # ==> . . .

# If they want to run something in single user mode, might as well run it...
for i in /etc/rc1.d/S[0-9][0-9]* ; do
        # Check if the script is there.
        [ -x "$i" ] || continue
  # ==> Se il corrispondente file in $PWD *non* viene trovato,
  #+==> allora "continua" saltando all'inizio del ciclo.

        # Reject backup files and files generated by rpm.
        case "$1" in
                *.rpmsave|*.rpmorig|*.rpmnew|*~|*.orig)
                        continue;;
        esac
        [ "$i" = "/etc/rc1.d/S00single" ] && continue
  # ==> Imposta il nome dello script, ma non lo esegue ancora.
        $i start
done

  # ==> . . .

Importante

L'exit status di una lista and o di una lista or corrisponde all'exit status dell'ultimo comando eseguito.

Sono possibili ingegnose combinazioni di liste "and" e "or" , ma la loro logica potrebbe facilmente diventare aggrovigliata e richiedere un debugging approfondito.

false && true || echo false         # false

# Stesso risultato di
( false && true ) || echo false     # false
# Ma *non*
false && ( true || echo false )     # (non viene visualizzato niente)

#  Notate i raggruppamenti e la valutazione degli enunciati da sinistra a destra
#+ perché gli operatori logici "&&" e "||" hanno la stessa priorità.

#  È meglio evitare tali complessità, a meno che non sappiate cosa state facendo

#  Grazie, S.C.

Vedi Esempio A-7 e Esempio 7-4 per un'illustrazione dell'uso di una lista and / or per la verifica di variabili.