23.2. Variabili locali

Cosa rende una variabile locale?

variabili locali

Una variabile dichiarata come local è quella che è visibile solo all'interno del blocco di codice in cui appare. Ha "ambito" locale. In una funzione una variabile locale ha significato solo all'interno del blocco di codice della funzione.

Esempio 23-12. Visibilità di una variabile locale

#!/bin/bash
# Variabili globali e locali in una funzione.

funz ()
{
  local var_locale=23       # Dichiarata come variabile locale.
  echo                      # Utilizza il builtin 'local'.
  echo "\"var_locale\" nella funzione = $var_locale"
  var_globale=999           # Non dichiarata come locale.
                            # Viene impostata per default come globale.
  echo "\"var_globale\" nella funzione = $var_globale"
}

funz

#  Adesso controlliamo se la variabile locale "var_locale" esiste al di fuori
#+ della funzione.

echo
echo "\"var_locale\" al di fuori della funzione = $var_locale"
                              # $var_locale al di fuori della funzione =
                              # No, $var_locale non ha visibilità globale.
echo "\"var_globale\" al di fuori della funzione = $var_globale"
                              # $var_globale al di fuori della funzione = 999
                              # $var_globale è visibile globalmente
echo

exit 0
#  A differenza del C, una variabile Bash dichiarata all'interno di una funzione
#+ è locale "solo" se viene dichiarata come tale.

Attenzione

Prima che una funzione venga richiamata, tutte le variabili dichiarate all'interno della funzione sono invisibili al di fuori del corpo della funzione stessa, non soltanto quelle esplicitamente dichiarate come locali.

#!/bin/bash

funz ()
{
var_globale=37    #  Visibile solo all'interno del blocco della funzione
                  #+ prima che la stessa venga richiamata.
}                 #  FINE DELLA FUNZIONE

echo "var_globale = $var_globale"  #  var_globale =
                                   #  La funzione "funz" non è ancora stata 
                                   #+ chiamata, quindi $var_globale qui non è
                                   #+ visibile.

funz
echo "var_globale = $var_globale"  # var_globale = 37
                                   # È stata impostata richiamando la funzione.

23.2.1. Le variabili locali aiutano a realizzare la ricorsività.

Le variabili locali consentono la ricorsività, [1] ma questa pratica implica, generalmente, un carico computazionale elevato e, in definitiva, non viene raccomandata in uno script di shell. [2]

Esempio 23-13. Ricorsività per mezzo di una variabile locale

#!/bin/bash

#               fattoriale
#               ----------


# Bash permette la ricorsività?
# Ebbene, sì, ma...
# è così lenta che dovreste avere dei sassi al posto del cervello per usarla.


MAX_ARG=5
E_ERR_ARG=65
E_ERR_MAXARG=66


if [ -z "$1" ]
then
  echo "Utilizzo: `basename $0` numero"
  exit $E_ERR_ARG
fi

if [ "$1" -gt $MAX_ARG ]
then
  echo "Valore troppo grande (il massimo è 5)."
  #  Torniamo alla realtà.
  #  Se fosse necessario un numero maggiore di questo,
  #+ riscrivete lo script in un vero linguaggio di programmazione.
  exit $E_ERR_MAXARG
fi

fatt ()
{
  local numero=$1
  #  La variabile "numero" deve essere dichiarata locale,
  #+ altrimenti questa funzione non svolge il suo compito.
  if [ "$numero" -eq 0 ]
  then
      fattoriale=1    # Il fattoriale di 0 è 1.
  else
      let "decrnum = numero - 1"
      fatt $decrnum  #  Chiamata ricorsiva della funzione 
                     #+ (la funzione richiama sé stessa).
      let "fattoriale = $numero * $?"
   fi

   return $fattoriale
}

fatt $1
echo "Il fattoriale di $1 è $?."

exit 0

Vedi anche Esempio A-16 per una dimostrazione di ricorsività in uno script. Si faccia attenzione che la ricorsività sfrutta intensivamente le risorse, viene eseguita lentamente e, di conseguenza, il suo uso, in uno script, non è appropriato.

Note

[1]

Herbert Mayer definisce la ricorsività come ". . . esprimere un algoritmo usando una versione semplificata di quello stesso algoritmo. . ." Una funzione ricorsiva è quella che richiama sé stessa.

[2]

Troppi livelli di ricorsività possono mandare in crash lo script con un messaggio di segmentation fault.

#!/bin/bash

#  Attenzione: è probabile che l'esecuzione di questo script blocchi il sistema!
#  Se siete fortunati, verrete avvertiti da un segmentation fault prima che 
#+ tutta la memoria disponibile venga occupata.

funzione_ricorsiva ()
{
echo "$1"     # Fa fare qualcosa alla funzione, accelerando il segfault.
(( $1 < $2 )) && funzione_ricorsiva $(( $1 + 1 )) $2;
#  Finché il primo parametro è inferiore al secondo,
#+ il primo viene incrementato ed il tutto si ripete.
}

funzione_ricorsiva 1 50000  # Ricorsività di 50,000 livelli!
#  Molto probabilmente segmentation fault (in base alla dimensione dello stack,
#+ impostato con ulimit -m).

#  Una ricorsività così elevata potrebbe causare un segmentation fault
#+ anche in un programma in C, a seguito dell'uso di tutta la memoria 
#+ allocata nello stack.


echo "Probabilmente questo messaggio non verrà visualizzato."
exit 0  # Questo script non terminarà normalmente.

#  Grazie, Stéphane Chazelas.