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.