| Guida avanzata di scripting Bash: Un'approfondita esplorazione dell'arte dello scripting di shell | ||
|---|---|---|
| Indietro | Capitolo 9. Variabili riviste | Avanti |
Ipotizziamo che il valore di una variabile sia il nome di una seconda variabile. È in qualche modo possibile recuperare il valore di questa seconda variabile dalla prima? Per esempio, se a=lettera_alfabeto e lettera_alfabeto=z, può una referenziazione ad a restituire z? In effetti questo è possibile e prende il nome di referenziazione indiretta. Viene utilizzata l'insolita notazione eval var1=\$$var2.
Esempio 9-23. Referenziazioni indirette
#!/bin/bash
# ind-ref.sh: Referenziazione indiretta a variabile.
# Accedere al contenuto del contenuto di una variabile.
a=lettera_alfabeto # La variabile "a" contiene il nome di un'altra variabile.
lettera_alfabeto=z
echo
# Referenziazione diretta.
echo "a = $a" # a = lettera_alfabeto
# Referenziazione indiretta.
eval a=\$$a
echo "Ora a = $a" # Ora a = z
echo
# Proviamo a modificare la referenziazione di secondo-ordine.
t=tabella_cella_3
tabella_cella_3=24
echo "\"tabella_cella_3\" = $tabella_cella_3" # "tabella_cella_3" = 24
echo -n "\"t\" dereferenziata = "; eval echo \$$t # "t" dereferenziata = 24
# In questo semplice caso, funziona anche quello che segue (perché?).
# eval t=\$$t; echo "\"t\" = $t"
echo
t=tabella_cella_3
NUOVO_VAL=387
tabella_cella_3=$NUOVO_VAL
echo "Valore di \"tabella_cella_3\" modificato in $NUOVO_VAL."
echo "\"tabella_cella_3\" ora $tabella_cella_3"
echo -n "\"t\" dereferenziata "; eval echo \$$t
# "eval" ha due argomenti "echo" e "\$$t" (impostata a $tabella_cella_3)
echo
# (Grazie a Stephane Chazelas, per aver chiarito il comportamento precedente.)
# Un altro metodo è quello della notazione ${!t}, trattato nella
#+ sezione "Bash, versione 2". Vedi anche ex78.sh.
exit 0 |
Qual'è l'utilità pratica della referenziazione indiretta delle variabili? Fornire a Bash un po' delle funzionalità dei puntatori del C, ad esempio, nella ricerca nelle tabelle. Nonché avere qualche altra interessantissima applicazione. . . .
Nils Radtke mostra come realizzare nomi di variabili "dinamici" e valutarne il contenuto. Questo può risultare utile quando occorre "includere" dei file di configurazione con source.
#!/bin/bash
# ---------------------------------------------------------------------
# Questo file può essere "caricato" da un altro file tramite "source".
isdnMioProviderReteRemota=172.16.0.100
isdnTuoProviderReteRemota=10.0.0.10
isdnServizioOnline="MioProvider"
# ---------------------------------------------------------------------
reteRemota=$(eval "echo \$$(echo isdn${isdnServizioOnline}ReteRemota)")
reteRemota=$(eval "echo \$$(echo isdnMioProviderReteRemota)")
reteRemota=$(eval "echo \$isdnMioProviderReteRemota")
reteRemota=$(eval "echo $isdnMioProviderReteRemota")
echo "$reteRemota" # 172.16.0.100
# ================================================================
# E fa ancor meglio.
# Considerate il frammento seguente dove viene inizializzata una
#+ variabile di nome getSparc, ma manca getIa64:
verMirrorArch () {
arch="$1";
if [ "$(eval "echo \${$(echo get$(echo -ne $arch |
sed 's/^\(.\).*/\1/g' | tr 'a-z' 'A-Z'; echo $arch |
sed 's/^.\(.*\)/\1/g')):-falso}")" = vero ]
then
return 0;
else
return 1;
fi;
}
getSparc="vero"
unset getIa64
verMirrorArch sparc
echo $? # 0
# Vero
verMirrorArch Ia64
echo $? # 1
# Falso
# Note:
# ----
# Anche la parte del nome della variabile da-sostituire viene costruita
#+ esplicitamente.
# I parametri passati a verMirrorArch sono in lettere minuscole.
# Il nome della variabile è formato da due parti: "get" e "Sparc" . . . |
Esempio 9-24. Passare una referenziazione indiretta a awk
#!/bin/bash
# Altra versione dello script "column totaler"
#+ che aggiunge una colonna (contenente numeri) nel file di destinazione.
# Qui viene utilizzata la referenziazione indiretta.
ARG=2
E_ERR_ARG=65
if [ $# -ne "$ARG" ] # Verifica il corretto nr. di argomenti da riga
#+ di comando.
then
echo "Utilizzo: `basename $0` nomefile numero_colonna"
exit $E_ERR_ARG
fi
nomefile=$1
numero_colonna=$2
#===== Fino a questo punto è uguale all'originale =====#
# Script awk di più di una riga vengono invocati con awk ' ..... '
# Inizio script awk.
# ----------------------------------------------------------
awk "
{ totale += \$${numero_colonna} # referenziazione indiretta
}
END {
print totale
}
" "$nomefile"
# ------------------------------------------------
# Fine script awk.
# La referenziazione indiretta evita le difficoltà della referenziazione
#+ di una variabile di shell all'interno di uno script awk incorporato.
# Grazie, Stephane Chazelas.
exit 0 |
![]() | Questo metodo è un po' complicato. Se la seconda variabile modifica il proprio valore, allora la prima deve essere correttamente dereferenziata (come nell'esempio precedente). Fortunatamente, la notazione ${!variabile}, introdotta con la versione 2 di Bash (vedi Esempio 34-2 e Esempio A-23), rende la referenziazione indiretta più intuitiva. |