Les constructions case et select ne sont pas techniquement des boucles puisqu' elles n'exécutent pas un bloc de code de façon itérative. Néanmoins, comme les boucles, elles orientent le flot d'exécution du programme suivant certaines conditions au début ou à la fin du bloc.
Contrôler le flot du programme dans un bloc de code
La construction case est l'équivalent shell de switch en C/C++. Elle permet le branchement vers un bloc parmi un certain nombre de blocs de code, suivant des tests de condition. Elle agit comme une espèce de raccourcis pour de multiples instructions if/then/else et est un outil approprié pour la création de menus.
case "$variable" in
"$condition1" )
commande...
;;
"$condition2" )
commande...
;;
esac
Exemple 10.24. Utiliser case
#!/bin/bash # Tester des suites de caractères. echo; echo "Appuyez sur une touche, puis faites ENTER." read Touche case "$Touche" in [[:lower:]] ) echo "Lettre minuscule";; [[:upper:]] ) echo "Lettre majuscule";; [0-9] ) echo "Nombre";; * ) echo "Ponctuation, espace blanc ou autre";; esac # Permet un ensemble de caractères dans des [crochets]. #+ ou des ensembles POSIX dans des [[crochets doubles]]. # Dans la première version de cet exemple, #+ les tests des caractères minuscules/majuscules étaient #+ [a-z] et [A-Z]. # Ceci ne fonctionne plus avec certaines locales et/ou distributions Linux. # POSIX est plus portable. # Merci à Frank Wang de me l'avoir fait remarquer. # Exercice : # --------- # Ce script accepte un simple appui sur une touche, puis se termine. # Modifiez le script pour qu'il accepte une saisie répétée, # rapportez chaque appui sur une touche, et terminez lors de l'appui sur "X". # Astuce : mettre tout dans une boucle "while". exit 0
Exemple 10.25. Créer des menus en utilisant case
#!/bin/bash # Base de données d'adresse. clear # Efface l'écran. echo " Liste de Contacts" echo " -----------------" echo "Choisissez une des personnes suivantes:" echo echo "[E]vans, Roland" echo "[J]ones, Mildred" echo "[S]mith, Julie" echo "[Z]ane, Morris" echo read personne case "$person" in # Notez que la variable est entre guillemets. "E" | "e" ) # Accepte les entrées en majuscule ou minuscule. echo echo "Roland Evans" echo "4321 Floppy Dr." echo "Hardscrabble, CO 80753" echo "(303) 734-9874" echo "(303) 734-9892 fax" echo "revans@zzy.net" echo "Business partner & old friend" ;; # Notez le double point-virgule pour terminer chaque option. "J" | "j" ) echo echo "Mildred Jones" echo "249 E. 7th St., Apt. 19" echo "New York, NY 10009" echo "(212) 533-2814" echo "(212) 533-9972 fax" echo "milliej@loisaida.com" echo "Ex-girlfriend" echo "Birthday: Feb. 11" ;; # Ajoutez de l'info pour Smith & Zane plus tard. * ) # Option par défaut. # Entrée vide (en appuyant uniquement sur la touche RETURN) vient ici aussi. echo echo "Pas encore dans la base de données." ;; esac echo # Exercice: # -------- # Modifier le script pour qu'il accepte plusieurs saisies, #+ au lieu de s'arrêter après avoir affiché une seule adresse. exit 0
Une utilisation exceptionnellement intelligente de case concerne le test des paramètres de ligne de commande.
#! /bin/bash case "$1" in "") echo "Usage: ${0##*/} <nomfichier>"; exit $E_PARAM;; # Pas de paramètres en lignes de commande #+ ou premier paramètre vide. # Notez que ${0##*/} est la substitution de paramètres ${var##modèle}. # Le résultat net est $0. -*) NOMFICHIER=./$1;; # Si le nom de fichier passé en premier argument ($1) #+ commence avec un tiret, #+ le remplacez par ./$1 #+ pour que les commandes suivants ne l'interprètent pas #+ comme une option. * ) NOMFICHIER=$1;; # Sinon, $1. esac
Voici un exemple plus direct de gestion de paramètres en ligne de commande :
#! /bin/bash while [ $# -gt 0 ]; do # Jusqu'à la fin des paramètres... case "$1" in -d|--debug) # paramètre "-d" ou "--debug" ? DEBUG=1 ;; -c|--conf) CONFFILE="$2" shift if [ ! -f $CONFFILE ]; then echo "Erreur : le fichier indiqué n'existe pas !" exit $E_FICHIERCONF # Erreur pour un fichier inexistant. fi ;; esac shift # Vérifiez le prochain ensemble de paramètres. done # À partir du script "Log2Rot" de Stefano Falsetto, #+ faisant partie de son paquetage "rottlog". # Utilisé avec sa permission.
Exemple 10.26. Utiliser la substitution de commandes pour générer la variable case
#!/bin/bash # case-cmd.sh #+ Utilisation de la substitution de commandes pour générer une variable "case". case $( arch ) in # "arch" renvoie l'architecture de la machine. # Équivalent à 'uname -m'... i386 ) echo "Machine 80386";; i486 ) echo "Machine 80486";; i586 ) echo "Machine Pentium";; i686 ) echo "Machine Pentium2+";; * ) echo "Autre type de machine";; esac exit 0
Une construction case peut filtrer les chaînes sur des paramètres de remplacement.
Exemple 10.27. Simple correspondance de chaîne
#!/bin/bash # match-string.sh: simple correspondance de chaînes de caractères chaines_correspondent () { CORRESPOND=0 CORRESPOND_PAS=90 PARAMS=2 # La fonction requiert deux arguments. MAUVAIS_PARAMS=91 [ $# -eq $PARAMS ] || return $MAUVAIS_PARAMS case "$1" in "$2") return $CORRESPOND;; * ) return $CORRESPOND_PAS;; esac } a=un b=deux c=trois d=deux chaines_correspondent $a # mauvais nombre de paramètres echo $? # 91 chaines_correspondent $a $b # pas de correspondance echo $? # 90 chaines_correspondent $b $d # correspondance echo $? # 0 exit 0
Exemple 10.28. Vérification d'une entrée alphabétique
#!/bin/bash # isalpha.sh: Utiliser une structure "case" pour filtrer une chaîne de #+ caractères. SUCCES=0 ECHEC=-1 est_alpha () # Teste si le *premier caractère* de la chaîne est alphabétique. { if [ -z "$1" ] # Pas d'argument passé? then return $ECHEC fi case "$1" in [a-zA-Z]*) return $SUCCES;; # Commence avec une lettre? * ) return $ECHEC;; esac } # Comparer ceci avec la fonction "isalpha ()" en C. est_alpha2 () # Teste si la *chaîne entière* est alphabétique. { [ $# -eq 1 ] || return $ECHEC case $1 in *[!a-zA-Z]*|"") return $ECHEC;; *) return $SUCCES;; esac } est_numerique () # Teste si la *chaîne entière* est numérique. { # En d'autres mots, teste si la variable est de type entier. [ $# -eq 1 ] || return $ECHEC case $1 in *[!0-9]*|"") return $ECHEC;; *) return $SUCCES;; esac } verif_var () # Interface à est_alpha (). { if est_alpha "$@" then echo "\"$*\" commence avec un caractère alpha." if est_alpha2 "$@" then # Aucune raison de tester si le premier caractère est non alpha. echo "\"$*\" contient seulement des caractères alpha." else echo "\"$*\" contient au moins un caractère non alpha." fi else echo "\"$*\" commence avec un caractère non alpha." # Aussi "non alpha" si aucun argument n'est passé. fi echo } verif_numerique () # Interface à est_numerique (). { if est_numerique "$@" then echo "\"$*\" contient seulement des chiffres [0 - 9]." else echo "\"$*\" a au moins un caractère qui n'est pas un chiffre." fi echo } a=23skidoo b=H3llo c=-What? d=What? e=`echo $b` # Substitution de commandes. f=AbcDef g=27234 h=27a34 i=27.34 verif_var $a verif_var $b verif_var $c verif_var $d verif_var $e verif_var $f verif_var # Pas d'argument passé, donc qu'arrive-t'il? # verif_numerique $g verif_numerique $h verif_numerique $i exit 0 # Script amélioré par S.C. # Exercice: # -------- # Ecrire une fonction 'est_flottant ()' qui teste les nombres en virgules #+ flottantes. # Astuce: La fonction duplique 'est_numerique ()', #+ mais ajoute un test pour le point décimal nécessaire.
La construction select, adoptée du Korn Shell, est encore un autre outil pour construire les menus.
select variable [in liste]
do
commande...
break
done
Ceci demande à l'utilisateur d'entrer un des choix présentés dans la variable liste. Notez que select utilise l'invite PS3 (#? ) par défaut mais que ceci peut être changé.
Exemple 10.29. Créer des menus en utilisant select
#!/bin/bash PS3='Choisissez votre légume favori : ' # Affiche l'invite. echo select legume in "haricot" "carotte" "patate" "ognion" "rutabaga" do echo echo "Votre légume favori est $legume." echo break # Qu'arriverait-il s'il n'y avait pas de 'break' ici ? #+ fin. done exit 0
Si une <replaceable>liste</replaceable> in est omise, alors select utilise la liste des arguments en ligne de commandes ($@) passée au script ou à la fonction dans lequel la construction select est intégrée.
Comparez ceci avec le comportement de la construction
for variable [in liste]
avec in <replaceable>liste</replaceable> omis.
Exemple 10.30. Créer des menus en utilisant select dans une fonction
#!/bin/bash PS3='Choisissez votre légume favori: ' echo choix_entre() { select legume # [in list] omise, donc 'select' utilise les arguments passés à la fonction. do echo echo "Votre légume favori est $vegetable." echo break done } choix_entre haricot riz carotte radis tomate épinard # $1 $2 $3 $4 $5 $6 # passé à la fonction choix_entre() exit 0
Voir aussi l'Exemple 34.3, « Simple application de base de données, utilisant les références de variables indirectes ».