34. Bash, version 2 et 3

34.1. Bash, version 2

La version actuelle de Bash, celle que vous avez sur votre machine, est la version 2.xx.y ou 3.xx.y.

bash$ echo $BASH_VERSION
2.05.b.0(1)-release
              

La mise à jour, version 2, du langage de script Bash classique ajoute les variables de type tableau, [94] l'expansion de chaînes de caractères et de paramètres, et une meilleure méthode pour les références de variables indirectes, parmi toutes les fonctionnalités.

Exemple 34.1. Expansion de 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 34.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 34.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 34.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.



[94] Chet Ramey a promit des tableaux associatifs (une fonctionnalité Perl) dans une future version de Bash. La version 3 n'en dispose toujours pas.