Que fait une variable locale ?
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.
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.
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.