23.2. Variables locales

Que fait une variable locale ?

variables locales

Une variable déclarée localement n'est visible qu'à l'intérieur du bloc de code dans laquelle elle apparaît. Elle a une « visibilité » locale. Dans une fonction, une variable locale n' a une signification qu'à l'intérieur du bloc de la fonction.

Exemple 23.12. Visibilité de la variable locale

#!/bin/bash
# Variables globales et locales à l'intérieur d'une fonction.

fonc ()
{
  local var_local=23       # Déclaré en tant que variable locale.
  echo                     # Utilise la commande intégrée locale.
  echo "\"var_local\" dans la fonction = $var_local"
  var_global=999           # Non déclarée en local.
                           # Retour en global.
  echo "\"var_global\" dans la fonction = $var_global"
}  

fonc

# Maintenant, voyons s'il existe une variable locale en dehors de la fonction.

echo
echo "\"var_loc\" en dehors de la fonction = $var_loc"
                                      # "var_loc" en dehors de la fonction = 
                                      # Non, $var_local n'est pas visible globalement.
echo "\"var_global\" en dehors de la fonction = $var_global"
                                      # "var_global" en dehors de la fontion = 999
                                      # $var_global est visible globalement.
echo                                  

exit 0
#  Au contraire de C, une variable Bash déclarée dans une fonction n'est locale
#+ que si elle est déclarée ainsi.


[Attention]

Attention

Avant qu'une fonction ne soit appelée, toutes les variables déclarées dans la fonction sont invisibles à l'extérieur du corps de la fonction, et pas seulement celles déclarées explicitement locales.

#!/bin/bash

func ()
{
var_globale=37   #  Visible seulement à l'intérieur du bloc de la fonction
                 #+ avant que la fonction ne soit appelée.
}                # FIN DE LA FONCTION

echo "var_globale = $var_globale" # var_globale =
                                  #  La fonction "func" n'a pas encore été appelée,
                                  #+ donc $var_globale n'est pas visible ici.

func
echo "var_globale = $var_globale" # var_globale = 37
                                  # A été initialisée par l'appel de la fonction.

23.2.1. Les variables locales rendent la récursion possible.

Les variables locales permettent la récursion [78] mais cette pratique implique généralement beaucoup de calculs supplémentaires et n'est vraiment pas recommandée dans un script shell. [79]

Exemple 23.13. Récursion en utilisant une variable locale

#!/bin/bash

#               facteurs
#               ---------


# Bash permet-il la récursion ?
# Eh bien, oui, mais...
# C'est si lent que vous devrez vous accrocher pour y arriver.


MAX_ARG=5
E_MAUVAIS_ARGS=65
E_MAUVAISE_ECHELLE=66


if [ -z "$1" ]
then
  echo "Usage : `basename $0` nombre"
  exit $E_MAUVAIS_ARGS
fi

if [ "$1" -gt $MAX_ARG ]
then
  echo "En dehors de l'échelle (5 est le maximum)."
  # Maintenant, allons-y.
  #  Si vous souhaitez une échelle plus importante, réécrivez-le dans un vrai
  #+ langage de programmation.
  exit $E_MAUVAISE_ECHELLE
fi  

fact ()
{
  local nombre=$1
  # La variable "nombre" doit être déclarée en local.
  # Sinon cela ne fonctionne pas.
  if [ "$nombre" -eq 0 ]
  then
    factoriel=1    # Le factoriel de 0 = 1.
  else
    let "decrnum = nombre - 1"
    fact $decrnum  # Appel à la fonction récursive (la fonction s'appelle elle-même).
    let "factoriel = $nombre * $?"
  fi

  return $factoriel
}

fact $1
echo "Le factoriel de $1 est $?."

exit 0

Voir aussi l'Exemple A.16, « primes: Générer des nombres premiers en utilisant l'opérateur modulo » pour un exemple de récursion dans un script. Faites attention que la récursion demande beaucoup de ressources et s'exécute lentement. Son utilisation n'est donc pas appropriée dans un script.



[78] Herbert Mayer définit la récursion comme « ...l'expression d'un algorithme utilisant une version plus simple de ce même algorithme... » Une fonction récursive s'appelle elle-même.

[79] Trop de niveaux de récursion pourrait arrêter brutalement un script avec une erreur de segmentation.

#!/bin/bash

#  Attention: Lancer ce script pourrait empêcher le bon fonctionnement de votre
#+ système !
#  Si vous êtes chanceux, il finira avec une erreur de segmentation avant
#+ d'avoir utiliser toute la mémoire disponible.

fonction_recursive ()
{
echo "$1"     # Fait en sorte que le fonction fait quelque chose et accélère le "segfault".
(( $1 < $2 )) && fonction_recursive $(( $1 + 1 )) $2;
#  Aussi longtemps que le premier paramètres est plus petit que le second,
#+ incrémente le premier et fait une récursion.
}

fonction_recursive 1 50000  # Récursion sur 50.000 niveaux!
#  Grande chance d'obtenir une erreur de segmentation (ceci dépendant de la
#+ taille de la pile, configurée avec ulimit -m).

#  Une récursion d'une telle profondeur peut même arrêter un programme C avec
#+ une erreur de segmentation, suite à l' utilisation de toute la mémoire
#+ allouée à la pile.

echo "Ceci ne s'affichera probablement pas."
exit 0  # Ce script ne finira par normalement.

# Merci, Stéphane Chazelas.