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. |