La version actuelle de Bash, celle que vous avez sur votre machine, est très probablement la version 2.xx.yy 3.xx.yy ou ou 4.xx.yy.
bash$ echo $BASH_VERSION 3.2.25(1)-release
La mise à jour de la version 2 du langage de script Bash classique ajoute les variables de type tableau, l'expansion de chaînes de caractères et de paramètres ainsi qu'une meilleure méthode pour les références de variables indirectes, entre autres fonctionnalités.
Exemple 37.1. Expansion d'une chaîne de caractères
#!/bin/bash # Expansion de chaînes de caractères. # Introduit avec la version 2 de Bash. # Les chaînes de caractères de la forme $'xxx' ont les caractères d'échappement # standard interprétés. echo $'Trois cloches sonnant à la fois \a \a \a' # Pourrait sonner seulement une fois sur certains terminaux. echo $'Trois retours chariot \f \f \f' echo $'10 retours chariot \n\n\n\n\n\n\n\n\n\n' echo $'\102\141\163\150' # Bash # Équivalent en octal des caractères. exit 0
Exemple 37.2. Références de variables indirectes - la nouvelle façon
#!/bin/bash # Référencement de variables indirectes. # Ceci a quelques-uns des attributs du C++. a=lettre_de_l_alphabet lettre_de_l_alphabet=z echo "a = $a" # Référence directe. echo "Maintenant a = ${!a}" # Référence indirecte. # La notation ${!variable} est bien supérieure à l'ancien "eval var1=\$$var2" echo t=cellule_table_3 cellule_table_3=24 echo "t = ${!t}" # t = 24 cellule_table_3=387 echo "La valeur de t a changé en ${!t}" # 387 # Ceci est utile pour référencer les membres d'un tableau ou d'une table, # ou pour simuler un tableau multi-dimensionnel. # Une option d'indexage (analogue à un pointeur arithmétique) aurait été bien. #+ Sigh. exit 0
Exemple 37.3. Simple application de base de données, utilisant les références de variables indirectes
#!/bin/bash # resistor-inventory.sh # Simple base de données utilisant le référencement indirecte de variables. # ============================================================== # # Données B1723_value=470 # Ohms B1723_powerdissip=.25 # Watts B1723_colorcode="yellow-violet-brown" # Bandes de couleurs B1723_loc=173 # Où elles sont B1723_inventory=78 # Combien B1724_value=1000 B1724_powerdissip=.25 B1724_colorcode="brown-black-red" B1724_loc=24N B1724_inventory=243 B1725_value=10000 B1725_powerdissip=.25 B1725_colorcode="brown-black-orange" B1725_loc=24N B1725_inventory=89 # ============================================================== # echo PS3='Entrez le numéro du catalogue : ' echo select numero_catalogue in "B1723" "B1724" "B1725" do Inv=${numero_catalogue}_inventory Val=${numero_catalogue}_value Pdissip=${numero_catalogue}_powerdissip Loc=${numero_catalogue}_loc Ccode=${numero_catalogue}_colorcode echo echo "Catalogue numéro $numero_catalogue :" echo "Il existe ${!Inv} résistances de [${!Val} ohm / ${!Pdissip} watt] en stock." echo "Elles sont situées dans bin # ${!Loc}." echo "Leur code couleur est \"${!Ccode}\"." break done echo; echo # Exercice : # --------- # Réécrire ce script en utilisant des tableaux, plutôt qu'en utilisant le #+ référencement indirecte des variables. # Quelle méthode est plus logique et intuitive ? # Notes : # ------ # Les scripts shells sont inappropriés pour tout, sauf des applications simples #+ de base de données, et, même là, cela implique des astuces. # Il est bien mieux d'utiliser un langage supportant nativement les structures #+ de données, tels que C++ ou Java (voire même Perl). exit 0
Exemple 37.4. Utiliser des tableaux et autres astuces pour gérer quatre mains aléatoires dans un jeu de cartes
#!/bin/bash # Cartes : # Gère quatre mains d'un jeu de cartes. NON_RECUPERE=0 RECUPERE=1 DUPE_CARD=99 LIMITE_BASSE=0 LIMITE_HAUTE=51 CARTES_DANS_SUITE=13 CARTES=52 declare -a Jeu declare -a Suites declare -a Cartes # Le script aurait été plus simple à implémenter et plus intuitif #+ avec un seul tableau à trois dimensions. # Peut-être qu'une future version de Bash gèrera des tableaux multi-dimensionnels. initialise_Jeu () { i=$LIMITE_BASSE until [ "$i" -gt $LIMITE_HAUTE ] do Jeu[i]=$NON_RECUPERE # Initialise chaque carte d'un "Jeu" comme non récupérée. let "i += 1" done echo } initialise_Suites () { Suites[0]=C #Carreaux Suites[1]=D #Piques Suites[2]=H #Coeurs Suites[3]=S #Trèfles } initialise_Cartes () { Cartes=(2 3 4 5 6 7 8 9 10 J Q K A) # Autre méthode pour initialiser un tableau. } recupere_une_carte () { numero_carte=$ALEATOIRE let "numero_carte %= $CARTES" if [ "${Jeu[numero_carte]}" -eq $NON_RECUPERE ] then Jeu[numero_carte]=$RECUPERE return $numero_carte else return $DUPE_CARD fi } analyse_carte () { nombre=$1 let "suit_nombre = nombre / CARTES_DANS_SUITE" suite=${Suites[suit_nombre]} echo -n "$suit-" let "no_carte = nombre % CARTES_DANS_SUITE" Carte=${Cartes[no_carte]} printf %-4s $Carte # Affiche proprement les cartes. } recherche_nombre_aleatoire () # Générateur de nombres aléatoires. { # Que se passe-t'il si vous ne faites pas cela ? recherche=`eval date +%s` let "recherche %= 32766" ALEATOIRE=$recherche # Quelles sont les autres méthodes de génération de nombres aléatoires ? } gere_cartes () { echo cartes_recuperees=0 while [ "$cartes_recuperees" -le $LIMITE_HAUTE ] do recupere_une_carte t=$? if [ "$t" -ne $DUPE_CARD ] then analyse_carte $t u=$cartes_recuperees+1 # Retour à un indexage simple (temporairement). Pourquoi ? let "u %= $CARTES_DANS_SUITE" if [ "$u" -eq 0 ] # Condition if/then imbriquée. then echo echo fi # Mains séparées. let "cartes_recuperees += 1" fi done echo return 0 } # Programmation structurée : # La logique entière du programme est modularisée en fonctions. #================ recherche_nombre_aleatoire initialise_Jeu initialise_Suites initialise_Cartes gere_cartes #================ exit 0 # Exercice 1 : # Ajouter des commentaires détaillées de ce script. # Exercice 2 : # Ajouter une routine (fonction) pour afficher chaque main triée par suite. # Vous pouvez ajouter d'autres fonctionnalités suivant vos souhaits. # Exercice 3 : # Simplifier et améliorer la logique du script.