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 sont un outil intéressant pour écrire du code récursif, mais cette pratique implique généralement un grand moment de réflexion et n'est réellement pas recommendée dans un script shell. [91]
Exemple 23.14. 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.
[87] Autrement connue sous le nom de redondance.
[88] Autrement connue sous le nom de tautologie.
[89] Autrement connue sous le nom de métaphore.
[90] Autrement connue sous le nom de fonction récursive.
[91] 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.