4.4. Tipi speciali di variabili

variabili locali

sono variabili visibili solo all'interno di un blocco di codice o funzione (vedi anche variabili locali in funzioni)

variabili d'ambiente

sono variabili relative al comportamento della shell e all'interfaccia utente

Nota

Più in generale, ogni processo possiede un proprio "ambiente", ovvero un gruppo di variabili contenenti delle informazioni a cui il processo fa riferimento. Da questo punto di vista, la shell si comporta come qualsiasi altro processo.

Ogni volta che la shell viene eseguita crea le variabili di shell che corrispondono alle sue variabili d'ambiente. L'aggiornamento o l'aggiunta di nuove variabili di shell provoca l'aggiornamento del suo ambiente. Tutti i processi generati dalla shell (i comandi eseguiti) ereditano questo ambiente.

Attenzione

Lo spazio assegnato all'ambiente è limitato. Creare troppe variabili d'ambiente, o se alcune occupano eccessivo spazio, potrebbe causare problemi.

bash$ eval "`seq 10000 | sed -e 's/.*/export var&=ZZZZZZZZZZZZZZ/'`"

bash$ du
bash: /usr/bin/du: Argument list too long
	          

(Grazie a Stéphane Chazelas per i chiarimenti e per aver fornito l'esempio.)

Se uno script imposta delle variabili d'ambiente, è necessario che vengano "esportate", cioè trasferite all'ambiente dei programmi che verranno eseguiti. Questo è il compito del comando export.

Nota

Uno script può esportare le variabili solo verso i processi figli, vale a dire solo nei confronti dei comandi o dei processi che vengono iniziati da quel particolare script. Uno script eseguito da riga di comando non può esportare le variabili all'indietro, verso l'ambiente precedente. Allo stesso modo, i processi figli non possono esportare le variabili all'indietro verso i processi genitori che li hanno generati.

Definizione: un processo figlio iè un sottoprocesso lanciato da un altro processo, il genitore.

---

parametri posizionali

rappresentano gli argomenti passati allo script da riga di comando: $0, $1, $2, $3 . . .

$0 contiene il nome dello script stesso, $1 è il primo argomento, $2 il secondo, $3 il terzo, ecc.. [1] Dopo $9 il numero degli argomenti deve essere racchiuso tra parentesi graffe, per esempio, ${10}, ${11}, ${12}.

Le variabili speciali $* e $@ forniscono il numero di tutti i parametri posizionali passati.

Esempio 4-5. Parametri posizionali

#!/bin/bash

# Eseguite lo script con almeno 10 parametri, per esempio
# ./nomescript 1 2 3 4 5 6 7 8 9 10
MINPARAM=10

echo

echo "Il nome dello script è \"$0\"."
# Aggiungete ./ per indicare la directory corrente
echo "Il nome dello script è \"`basename $0`\"."
# Visualizza il percorso del nome (vedi 'basename')

echo

if [ -n "$1" ]                #  Utilizzate il quoting per la variabile
                              #+ da verificare.
then
 echo "Il parametro #1 è $1"  # È necessario il quoting
                              #+ per visualizzare il #
fi 

if [ -n "$2" ]
then
 echo "Il parametro #2 è $2"
fi 

if [ -n "$3" ]
then
 echo "Il parametro #3 è $3"
fi 

# ...


if [ -n "${10}" ]  #  I parametri > $9 devono essere racchiusi 
                   #+ tra {parentesi graffe}.
then
 echo "Il parametro #10 è ${10}"
fi 

echo "-----------------------------------"
echo "In totale i parametri passati sono;: "$*""

if [ $# -lt "$MINPARAM" ]
then
  echo
  echo "Lo script ha bisogno di almeno $MINPARAM argomenti da riga di comando!"
fi  

echo

exit 0

La notazione parentesi graffe, applicata ai parametri posizionali, può essere facilmente impiegata per la referenziazione all'ultimo argomento passato allo script da riga di comando. Questo richiede anche la referenziazione indiretta.

arg=$#                     # Numero di argomenti passati.
ultimo_argomento=${!arg}
# Oppure:   ultimo_argomento=${!#}
#           (Grazie, Chris Monson.)  
# Notate che ultimo_argomento=${!$#} non funziona.

Alcuni script possono eseguire compiti diversi in base al nome con cui vengono invocati. Affinché questo possa avvenire, lo script ha bisogno di verificare $0, cioè il nome con cui è stato invocato. Naturalmente devono esserci dei link simbolici ai nomi alternativi dello script. Vedi Esempio 15-2.

Suggerimento

Se uno script si aspetta un parametro passato da riga di comando, ma è stato invocato senza, ciò può causare un assegnamento del valore nullo alla variabile che deve essere inizializzata da quel parametro. Di solito, questo non è un risultato desiderabile. Un modo per evitare questa possibilità è aggiungere un carattere supplementare ad entrambi i lati dell'enunciato di assegnamento che utilizza il parametro posizionale.

variabile1_=$1_  # Invece di variabile1=$1
#  Questo evita qualsiasi errore, anche se non è presente 
#+ il parametro posizionale.

argomento_critico01=$variabile1_

#  Il carattere aggiunto può essere tolto più tardi in questo modo:
variabile1=${variabile1_/_/}   
#  Si hanno effetti collaterali solo se $variabile1_ inizia col
#+ trattino di sottolineatura (underscore).
#  È stato utilizzato uno dei modelli di sostituzione di parametro che verrà 
#+ trattata successivamente. 
# (Se si omette il sostituto si ottiene una cancellazione.)

#  Un modo più diretto per gestire la situazione è una
#+ semplice verifica della presenza dei parametri posizionali attesi.
if [ -z $1 ]
then
  exit $MANCA_PARAM_POSIZIONALE
fi

#  Tuttavia, come ha evidenziato Fabian Kreutz,
#+ il metodo precedente può generare degli effetti collaterali inattesi.
#  Un sistema migliore è rappresentato dalla sostituzione di parametro:
#         ${1:-$ValDefault}
#  Vedi la sezione "Sostituzione di parametro"
#+ del capitolo "Variabili riviste".  

---

Esempio 4-6. verifica del nome di dominio: wh, whois

#!/bin/bash
# ex18.sh

# Esegue una verifica 'whois nome-dominio' su uno dei 3 server:
#                    ripe.net, cw.net, radb.net

# Inserite questo script - con nome 'wh' - in /usr/local/bin

# Sono richiesti i seguenti link simbolici:
# ln -s /usr/local/bin/wh /usr/local/bin/wh-ripe
# ln -s /usr/local/bin/wh /usr/local/bin/wh-cw
# ln -s /usr/local/bin/wh /usr/local/bin/wh-radb

E_NOARG=65

if [ -z "$1" ]
then
  echo "Utilizzo: `basename $0` [nome-dominio]"
  exit $E_NOARG
fi

# Verifica il nome dello script e interroga il server adeguato.
case `basename $0` in  # Oppure:    case ${0##*/} in
    "wh"     ) whois $1@whois.ripe.net;;
    "wh-ripe") whois $1@whois.ripe.net;;
    "wh-radb") whois $1@whois.radb.net;;
    "wh-cw"  ) whois $1@whois.cw.net;;
    *        ) echo "Utilizzo: `basename $0` [nome-dominio]";;
esac 

exit $?

---

Il comando shift riassegna i parametri posizionali, spostandoli di una posizione verso sinistra.

$1 <--- $2, $2 <--- $3, $3 <--- $4, ecc.

Il vecchio $1 viene sostituito, ma $0 (il nome dello script) non cambia. Se si utilizza un numero elevato di parametri posizionali, shift permette di accedere a quelli dopo il 10, sebbene questo sia possibile anche con la notazione {parentesi graffe}.

Esempio 4-7. Uso di shift

#!/bin/bash
# Utilizzo di 'shift' per elaborare tutti i parametri posizionali.

#  Chiamate lo script shft ed invocatelo con alcuni parametri, per esempio
#          ./shft a b c def 23 skidoo

until [ -z "$1" ]  # Finché ci sono parametri...
do
  echo -n "$1 "
  shift
done

echo               # Linea extra.

exit 0

Il comando shift può avere un numero come argomento che indica quante posizioni vanno spostate.

#!/bin/bash
# shift-past.sh

shift 3    # Si sposta di 3 posizioni.
#  n=3; shift $n
#  Ha lo stesso effetto.
			    
echo "$1"
			    
exit 0
			    
			    
$ sh shift-past.sh 1 2 3 4 5
4

Nota

Il comando shift agisce allo stesso modo sui parametri passati ad una funzione. Vedi Esempio 33-15.

Note

[1]

È il processo che chiama lo script che imposta il parametro $0. Per convenzione, questo parametro è il nome dello script. Vedi la pagina di manuale di execv.