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 [80] mais cette pratique implique généralement beaucoup de calculs supplémentaires et n'est vraiment pas recommandée dans un script shell. [81]
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.
[80] 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.
[81] 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.