Variables et types#
Bash est un langage à typage faible et dynamique : par défaut, toute variable est une chaîne de caractères, et le contexte détermine si elle est traitée comme un entier, un tableau ou une autre valeur. Cette flexibilité est pratique pour les scripts simples, mais elle est aussi source de subtilités — et parfois de bugs — que seule une bonne compréhension des mécanismes sous-jacents permet d’éviter. Ce chapitre couvre la déclaration et l’affectation des variables, les différents types de guillemets, la gestion de l’environnement, les variables spéciales du shell, la substitution de commandes et l’arithmétique en Bash.
Déclaration et affectation#
En Bash, une variable se déclare simplement en l’affectant. Il n’y a pas de mot-clé de déclaration obligatoire (contrairement à d’autres langages). La règle la plus importante est qu’il ne doit pas y avoir d’espaces autour du signe = :
Définition 20 (Règle d’affectation en Bash)
L’affectation d’une variable suit la syntaxe stricte NOM=valeur, sans espace autour du signe égal. La présence d’un espace transformerait la ligne en appel de commande : NOM = valeur serait interprété comme « exécuter la commande NOM avec les arguments = et valeur », ce qui produit généralement une erreur de type « commande introuvable ».
Par convention, les variables d’environnement exportées et les constantes sont nommées en MAJUSCULES_AVEC_UNDERSCORES, tandis que les variables locales aux scripts utilisent des minuscules_avec_underscores.
# Affectation correcte
prénom="Alice"
âge=32
chemin_config="/etc/mon_app/config.yaml"
# ERREUR : espace autour de =
prénom = "Alice" # bash: prénom: command not found
# Les valeurs sans espaces n'ont pas besoin de guillemets
compteur=0
fichier=rapport.txt
# Mais les guillemets sont recommandés pour les chaînes
message="Bonjour, monde !"
# Affectation avec expansion immédiate
répertoire_courant=$(pwd)
horodatage=$(date +%Y%m%d_%H%M%S)
Pour lire la valeur d’une variable, on la préfixe du symbole $. Pour éviter les ambiguïtés lorsque le nom de la variable est suivi d’autres caractères alphanumériques, on l’entoure d’accolades ${} :
animal="chat"
echo $animal # chat
echo ${animal} # chat (équivalent, plus explicite)
echo "${animal}s" # chats (les accolades séparent le nom de la variable du 's')
echo "$animals" # (vide : la variable 'animals' n'existe pas)
Affichage : echo et printf#
Deux commandes permettent d’afficher du texte : echo et printf. Elles ont des comportements différents qu’il est important de comprendre.
```{prf:definition} echo vs printf
:label: definition-08-02
echo est la commande la plus simple pour afficher du texte. Elle ajoute automatiquement un retour à la ligne en fin de sortie. Son comportement avec les options (-n, -e) varie selon les implémentations (bash built-in, /bin/echo, ksh, etc.), ce qui la rend peu fiable dans les scripts portables. L’option -n supprime le retour à la ligne final, et -e active l’interprétation des séquences d’échappement comme \n, \t, \\.
printf est l’outil recommandé pour un affichage précis et portable. Sa syntaxe s’inspire de printf en C : printf FORMAT [ARGUMENTS...]. Le format peut contenir des spécificateurs (%s pour chaîne, %d pour entier, %f pour flottant, %x pour hexadécimal) et des séquences d’échappement (\n, \t, \\). Contrairement à echo, printf ne termine pas automatiquement par un retour à la ligne : il faut l’inclure explicitement dans le format.
```bash
# Exemples echo
echo "Bonjour" # Bonjour (avec \n final)
echo -n "Sans newline" # Sans newline (pas de \n)
echo -e "Tab:\there" # Tab: ici (si -e est supporté)
# Exemples printf — à préférer dans les scripts
printf "Bonjour\n" # Bonjour
printf "Nom : %s, Âge : %d\n" "Alice" 32 # Nom : Alice, Âge : 32
printf "Pi ≈ %.4f\n" 3.14159 # Pi ≈ 3.1416
printf "%05d\n" 42 # 00042 (zéro-padded)
printf "%-20s %10s\n" "Alice" "admin" # alignement colonne gauche/droite
printf "Hexadécimal : %x\n" 255 # Hexadécimal : ff
# printf dans une boucle pour générer un tableau
printf "%-15s %-10s %-5s\n" "Nom" "Ville" "Âge"
printf "%-15s %-10s %-5s\n" "---" "-----" "---"
for ligne in "Alice:Paris:32" "Bob:Lyon:25" "Carol:Marseille:41"; do
IFS=':' read -r nom ville âge <<< "$ligne"
printf "%-15s %-10s %-5s\n" "$nom" "$ville" "$âge"
done
Remarque 21
La règle pratique est simple : utilisez echo pour les messages rapides et interactifs dans le terminal, et printf pour tout affichage dans les scripts devant être précis, formaté ou portable. En particulier, printf '%s\n' "$variable" est plus sûr que echo "$variable" quand la variable pourrait commencer par - (ce qui serait interprété comme une option de echo).
Les guillemets : le mécanisme fondamental#
La gestion des guillemets est l’un des aspects les plus importants — et les plus mal compris — de Bash. Elle détermine comment les variables sont expansées, comment les espaces sont gérés et comment les caractères spéciaux sont interprétés.
Définition 21 (Les quatre mécanismes de citation en Bash)
Bash reconnaît quatre formes de citation, chacune avec un comportement distinct :
Guillemets doubles
"...": permettent l”interpolation des variables ($var), des substitutions de commandes ($(cmd)) et des expansions arithmétiques ($((expr))). Les caractères$,`,\et!conservent leur signification spéciale. Tous les autres caractères (espaces,*,?,{,}, etc.) sont traités littéralement.Guillemets simples
'...': aucune interprétation. Tout ce qui est entre guillemets simples est traité comme une chaîne littérale, y compris$, les backslashes et les retours à la ligne. Il est impossible d’inclure un guillemet simple à l’intérieur d’une chaîne à guillemets simples.Backticks
`cmd`: substitution de commande (remplacée par la sortie decmd). Obsolète : préférer$(cmd), qui est plus lisible et peut être imbriqué.Pas de guillemets : le shell effectue toutes les expansions (word splitting, globbing, etc.). Les espaces dans les valeurs de variables séparent les mots. À éviter autour des variables (
$varsans guillemets est dangereux sivarcontient des espaces ou des caractères spéciaux).
Guillemets doubles — interpolation contrôlée#
nom="Alice"
ville="New York"
# Interpolation de variable dans une chaîne
echo "Bonjour, $nom !" # Bonjour, Alice !
echo "Ville : ${ville}" # Ville : New York
# Les espaces sont préservés dans la valeur
echo "$ville" # New York (un seul argument)
echo $ville # New York (interprété comme deux mots : New et York)
# Interpolation de sous-commande
echo "Date : $(date +%Y-%m-%d)" # Date : 2024-03-15
echo "Fichiers : $(ls | wc -l)" # Fichiers : 42
# Backslash d'échappement dans les guillemets doubles
echo "Guillemet double : \"" # Guillemet double : "
echo "Backslash : \\" # Backslash : \
echo "Variable non interpolée : \$nom" # Variable non interpolée : $nom
Guillemets simples — texte littéral#
# Aucune interprétation
echo 'Bonjour, $nom !' # Bonjour, $nom ! (pas d'interpolation)
echo 'Date : $(date)' # Date : $(date) (pas de substitution)
echo 'Tab : \t' # Tab : \t (pas d'échappement)
# Utilité : passer des expressions régulières ou du code sans interférences
grep 'prix = \$[0-9]\+' catalogue.txt
sed 's/\(.*\)/[&]/' # pas d'expansion Bash des parenthèses
# Guillemet simple impossible à l'intérieur de guillemets simples
# Astuce : terminer, ajouter le guillemet échappé, recommencer
echo 'C'\''est une apostrophe' # C'est une apostrophe
# Ou utiliser $'...' (ANSI C quoting) :
echo $'C\'est une apostrophe' # C'est une apostrophe
La syntaxe $'...' — ANSI C quoting#
# Séquences d'échappement dans les guillemets simples (syntaxe $'...')
echo $'Ligne 1\nLigne 2' # Deux lignes
echo $'Tab\there' # Tab puis here
echo $'\a' # Bip sonore (bell)
echo $'\e[31mTexte rouge\e[0m' # Texte en rouge (codes ANSI)
# Caractères Unicode
echo $'\u00e9' # é
echo $'\u00e0' # à
echo $'\u2603' # ☃ (bonhomme de neige)
Remarque 22
La règle d’or du scripting Bash est de toujours entourer les variables de guillemets doubles : "$variable". Sans guillemets, une variable contenant des espaces sera soumise au word splitting (découpage en plusieurs mots) et au globbing (expansion des caractères *, ?, etc.), ce qui peut provoquer des comportements inattendus voire dangereux (imaginez rm $fichier si $fichier vaut * important.txt). Les guillemets doubles protègent de ces expansions non souhaitées tout en permettant l’interpolation.
Variables d’environnement#
L”environnement d’un processus est un ensemble de paires NOM=valeur héritées du processus parent et transmises aux processus enfants. Il constitue un mécanisme de configuration global.
Définition 22 (Variables d’environnement)
Une variable d’environnement est une variable Bash qui a été exportée : elle est transmise aux processus enfants créés par le shell courant. Une variable non exportée n’est visible que dans le shell qui l’a définie — ses enfants ne la voient pas.
La commande export NOM (ou export NOM=valeur) marque une variable pour l’exportation. La commande unset NOM supprime une variable (exportée ou non) de l’environnement courant.
Inspecter l’environnement#
# Lister toutes les variables d'environnement
env
printenv
# Afficher la valeur d'une variable spécifique
printenv PATH
printenv HOME
# Variables d'environnement importantes
echo $HOME # Répertoire personnel de l'utilisateur
echo $PATH # Chemins de recherche des exécutables
echo $USER # Nom de l'utilisateur courant
echo $SHELL # Shell par défaut de l'utilisateur
echo $LANG # Paramètre de langue et d'encodage
echo $TERM # Type de terminal
echo $EDITOR # Éditeur de texte par défaut
echo $PWD # Répertoire courant
echo $OLDPWD # Répertoire précédent (utilisé par cd -)
echo $HOSTNAME # Nom de la machine
Exporter des variables#
# Définir et exporter en une seule commande
export MA_VARIABLE="valeur"
# Définir puis exporter séparément
MA_VARIABLE="valeur"
export MA_VARIABLE
# Vérifier qu'une variable est bien exportée
export | grep MA_VARIABLE
# Exécuter une commande avec une variable d'environnement temporaire
NOM=Alice ./script.sh # La variable NOM est définie uniquement pour script.sh
# Méthode explicite avec env
env NOM=Alice PORT=8080 ./serveur.sh
# Supprimer une variable de l'environnement
unset MA_VARIABLE
# Supprimer de l'export sans supprimer la variable
export -n MA_VARIABLE
Modifier le PATH#
# Ajouter un répertoire au début du PATH (priorité maximale)
export PATH="/mon/répertoire/bin:$PATH"
# Ajouter à la fin (priorité minimale)
export PATH="$PATH:/mon/répertoire/bin"
# Afficher les répertoires du PATH, un par ligne
echo $PATH | tr ':' '\n'
# Trouver la localisation d'un exécutable
which python3
type python3 # Plus complet : alias, fonctions, builtins
command -v python3 # Portable, retourne le chemin sans message d'erreur
Variables spéciales du shell#
Bash définit un ensemble de variables spéciales dont les valeurs sont gérées automatiquement par le shell. Elles sont essentielles pour l’écriture de scripts robustes.
Définition 23 (Variables spéciales Bash)
Les variables spéciales ne peuvent pas être affectées directement (sauf quelques exceptions) :
Variable |
Signification |
|---|---|
|
Nom du script ou du shell en cours d’exécution |
|
Arguments positionnels passés au script ou à la fonction |
|
Arguments positionnels au-delà du 9e (accolades obligatoires) |
|
Tous les arguments positionnels, chaque argument étant un mot séparé (avec guillemets doubles : |
|
Tous les arguments positionnels en un seul mot (avec guillemets doubles : |
|
Nombre d’arguments positionnels |
|
Code de retour de la dernière commande exécutée (0 = succès, ≠ 0 = erreur) |
|
PID (identifiant de processus) du shell courant |
|
PID du dernier processus lancé en arrière-plan avec |
|
Options du shell courant (les flags actifs, comme |
|
Dernier argument de la commande précédente |
Utilisation des variables spéciales#
#!/usr/bin/env bash
# Démonstration des variables spéciales
echo "Nom du script : $0"
echo "Nombre d'arguments : $#"
echo "Premier argument : $1"
echo "Deuxième argument : $2"
echo "Tous les arguments (\$@) :"
for arg in "$@"; do
echo " - '$arg'"
done
# Code de retour
ls /répertoire_inexistant 2>/dev/null
echo "Code de retour de ls : $?" # 2
ls /tmp 2>/dev/null
echo "Code de retour de ls : $?" # 0 (succès)
# PID du shell
echo "Mon PID : $$"
# Lancer un processus en arrière-plan
sleep 100 &
echo "PID du processus en arrière-plan : $!"
La différence cruciale entre $@ et $*#
# Avec les arguments : "premier argument" "deuxième" "troisième"
# "$@" — chaque argument est un mot séparé (RECOMMANDÉ)
for arg in "$@"; do
echo "Arg : '$arg'"
done
# Arg : 'premier argument'
# Arg : 'deuxième'
# Arg : 'troisième'
# "$*" — tous les arguments en un seul mot
for arg in "$*"; do
echo "Arg : '$arg'"
done
# Arg : 'premier argument deuxième troisième'
# Sans guillemets, $@ et $* se comportent pareil (word splitting)
# — et c'est rarement ce qu'on veut
Substitution de commandes#
La substitution de commandes permet d’utiliser la sortie d’une commande comme valeur dans une expression. La forme moderne est $(commande).
# Stocker la sortie d'une commande dans une variable
date_actuelle=$(date +%Y-%m-%d)
fichiers=$(ls /tmp/*.log 2>/dev/null)
nb_processus=$(ps aux | wc -l)
# Utiliser directement dans une chaîne
echo "Rapport généré le $(date '+%d/%m/%Y à %H:%M')"
echo "Noyau : $(uname -r)"
echo "Espace libre : $(df -h / | awk 'NR==2 {print $4}')"
# Imbrication (possible avec $(), impossible avec backticks)
fichier_plus_récent=$(ls -t $(find . -name "*.log") | head -1)
# Capturer stdout et stderr séparément
résultat=$(commande 2>/tmp/erreurs.txt)
erreurs=$(cat /tmp/erreurs.txt)
# Capturer les deux ensemble
tout=$(commande 2>&1)
Remarque 23
La substitution $(commande) remplace les backticks `commande` qui sont l’ancienne syntaxe. Les backticks sont déconseillés car ils sont plus difficiles à lire (confusion visuelle avec les guillemets simples), ils ne peuvent pas être imbriqués facilement et leur comportement avec le backslash est plus complexe. La syntaxe $() est claire, imbriquée facilement et recommandée dans tous les scripts modernes.
Arithmétique en Bash#
Bash propose plusieurs mécanismes pour effectuer des calculs sur des entiers. Pour les calculs en virgule flottante, il faut faire appel à des outils externes.
Définition 24 (Mécanismes d’arithmétique en Bash)
Bash offre trois approches pour l’arithmétique sur les entiers :
$(( expression ))— expansion arithmétique : évalue une expression arithmétique et retourne le résultat sous forme de chaîne. C’est l’approche recommandée.(( expression ))— commande arithmétique : évalue l’expression pour son effet de bord (affectation) ou son code de retour (0 si l’expression est non nulle, 1 si elle est nulle — utile dans les conditions).let "expression"— ancienne syntaxe équivalente à(( )). Déconseillée au profit de(( )).
Pour les calculs en virgule flottante, il faut utiliser bc (calculatrice en ligne de commande) ou awk.
Arithmétique entière avec $(( ))#
# Opérations de base
echo $((2 + 3)) # 5
echo $((10 - 4)) # 6
echo $((3 * 7)) # 21
echo $((17 / 5)) # 3 (division entière)
echo $((17 % 5)) # 2 (modulo)
echo $((2 ** 10)) # 1024 (puissance)
# Avec des variables (pas besoin de $ à l'intérieur de (( )))
a=10
b=3
echo $((a + b)) # 13
echo $((a * b)) # 30
echo $((a / b)) # 3 (division entière)
# Affectation dans $(( ))
résultat=$((a ** 2 + b ** 2))
echo $résultat # 109
# Incrémentation
compteur=0
compteur=$((compteur + 1))
# Ou avec (( )) :
((compteur++))
((compteur += 5))
# Opérateurs bit à bit
echo $((0xFF)) # 255 (littéral hexadécimal)
echo $((10 & 6)) # 2 (AND bit à bit)
echo $((10 | 6)) # 14 (OR bit à bit)
echo $((10 ^ 6)) # 12 (XOR bit à bit)
echo $((~10)) # -11 (NOT bit à bit)
echo $((10 << 2)) # 40 (décalage gauche)
echo $((10 >> 1)) # 5 (décalage droit)
La commande arithmétique (( ))#
# (( )) retourne 0 (succès) si l'expression est non nulle
# et 1 (échec) si l'expression vaut 0 — utile dans les conditions
a=5
if (( a > 3 )); then
echo "$a est supérieur à 3"
fi
# Boucle avec compteur
for ((i=0; i<5; i++)); do
echo "Itération $i"
done
# Affectation conditionnelle
(( valeur = (a > 3) ? 100 : 0 )) # Opérateur ternaire
echo $valeur # 100
# Plusieurs affectations
((a = 10, b = 20, c = a + b))
echo $c # 30
Calculs en virgule flottante avec bc#
# bc lit des expressions depuis stdin
echo "scale=4; 355/113" | bc # 3.1415 (π approché)
echo "scale=2; sqrt(2)" | bc # 1.41
echo "scale=6; e(1)" | bc -l # 2.718281 (e, avec math library)
echo "scale=10; 4*a(1)" | bc -l # 3.1415926535 (π via arctan)
# Stocker dans une variable
π=$(echo "scale=10; 4*a(1)" | bc -l)
echo "π ≈ $π"
# Calcul avec des variables shell
prix=19.99
quantité=3
total=$(echo "scale=2; $prix * $quantité" | bc)
echo "Total : ${total}€" # Total : 59.97€
# Comparaison de flottants (bc retourne 0 ou 1)
if [ $(echo "$prix > 15.0" | bc) -eq 1 ]; then
echo "Prix supérieur à 15€"
fi
Calculs en virgule flottante avec awk#
# awk peut effectuer des calculs flottants directement
awk 'BEGIN {printf "%.4f\n", 355/113}' # 3.1416
awk 'BEGIN {printf "%.6f\n", sqrt(2)}' # 1.414214
awk 'BEGIN {printf "%.8f\n", exp(1)}' # 2.71828182
# Calcul à partir de variables shell
prix=19.99; quantité=3
awk "BEGIN {printf \"Total : %.2f€\n\", $prix * $quantité}"
La commande declare — typage explicite#
Bien que Bash soit à typage faible, la commande declare permet d’attribuer des attributs aux variables pour contrôler leur comportement.
```{prf:definition} Attributs de declare
:label: definition-08-07
La commande declare (ou son synonyme typeset) permet de définir des attributs sur les variables :
-r(readonly) : la variable ne peut plus être modifiée ni supprimée.-i(integer) : la valeur est traitée comme un entier. Toute affectation est évaluée arithmétiquement.-l(lowercase) : la valeur est automatiquement convertie en minuscules.-u(uppercase) : la valeur est automatiquement convertie en majuscules.-x(export) : équivalent àexport.-a(array) : déclare un tableau indexé.-A(associative array) : déclare un tableau associatif.-p: affiche la déclaration et la valeur de la variable.-f: s’applique aux fonctions.
```bash
# Variable en lecture seule
declare -r VERSION="1.0.0"
VERSION="2.0.0" # bash: VERSION: variable en lecture seule
# Variable entière (les affectations sont évaluées arithmétiquement)
declare -i compteur=0
compteur+=5 # compteur vaut 5
compteur="3+2" # compteur vaut 5 (évalué comme 3+2)
compteur="abc" # compteur vaut 0 (abc n'est pas un entier valide)
# Variables normalisées en casse
declare -l prénom="ALICE"
echo "$prénom" # alice
declare -u code="erreur_critique"
echo "$code" # ERREUR_CRITIQUE
# Afficher la déclaration complète d'une variable
declare -p PATH
declare -p BASH_VERSION
# Variables readonly du shell (non modifiables même avec declare)
echo $BASH_VERSION # Version de Bash (ex: 5.2.15(1)-release)
echo $BASH_PID # PID du Bash courant
echo $RANDOM # Nombre pseudo-aléatoire entre 0 et 32767
echo $LINENO # Numéro de la ligne courante dans le script
echo $SECONDS # Secondes écoulées depuis le démarrage du shell
Expansion de variables avancée#
Bash propose une syntaxe très riche pour manipuler les valeurs des variables directement dans les expansions ${}.
Exemple 19 (Valeurs par défaut et substitutions conditionnelles)
Bash dispose d’un ensemble d’opérateurs de substitution très puissants :
# ${variable:-valeur_défaut} : utiliser valeur_défaut si variable est vide ou non définie
echo "${NOM:-Inconnu}" # "Inconnu" si NOM n'est pas défini
# ${variable:=valeur_défaut} : affecter valeur_défaut si variable est vide ou non définie
echo "${TIMEOUT:=30}" # Affecte 30 à TIMEOUT et l'affiche
# ${variable:+valeur_alt} : utiliser valeur_alt si variable EST définie et non vide
echo "${DEBUG:+--verbose}" # Affiche "--verbose" seulement si DEBUG est défini
# ${variable:?message_erreur} : erreur fatale si variable est vide ou non définie
echo "${FICHIER:?Le fichier doit être spécifié}"
# Longueur d'une variable
chaîne="Bonjour"
echo ${#chaîne} # 7
# Extraction d'une sous-chaîne : ${variable:offset:longueur}
echo ${chaîne:2:3} # njo (3 caractères à partir du 2e)
echo ${chaîne: -3} # our (3 derniers caractères)
# Suppression de préfixe
chemin="/home/alice/documents/rapport.pdf"
echo ${chemin#*/} # home/alice/documents/rapport.pdf (supprime le plus court préfixe */)
echo ${chemin##*/} # rapport.pdf (supprime le plus long préfixe */)
# Suppression de suffixe
echo ${chemin%.*} # /home/alice/documents/rapport (supprime .pdf)
echo ${chemin%%/*} # (vide — supprime le plus long suffixe /*)
# Remplacement de sous-chaîne
echo ${chemin/alice/bob} # /home/bob/documents/rapport.pdf (première occurrence)
echo ${chemin//a/A} # /home/Alice/documents/rApport.pdf (toutes les occurrences)
## Visualisation : guillemets et interpolation
```{code-cell} python
:tags: [hide-input]
fig, axes = plt.subplots(2, 2, figsize=(16, 10))
fig.suptitle('Types de guillemets et comportements en Bash',
fontsize=15, fontweight='bold', y=1.01)
palette = sns.color_palette("muted", 6)
couleurs = {
'double': palette[0],
'simple': palette[1],
'aucun': palette[2],
'dollar': palette[3],
}
# --- Tableau comparatif des types de guillemets ---
ax = axes[0, 0]
ax.axis('off')
ax.set_title('Comportement des guillemets', fontsize=13, fontweight='bold')
types = [
('"..."', 'Doubles', 'Oui', 'Oui', 'Oui', 'Non', couleurs['double']),
("'...'", 'Simples', 'Non', 'Non', 'Non', 'Non', couleurs['simple']),
('Aucun', 'Aucun', 'Oui', 'Oui', 'Oui', 'Oui', couleurs['aucun']),
("$'...'", 'ANSI C', 'Non', 'Non', '\\n \\t', 'Non', couleurs['dollar']),
]
colonnes = ['Syntaxe', 'Type', 'Vars $', 'Cmds $()', 'Échap.', 'Globbing']
largeurs = [0.14, 0.14, 0.12, 0.14, 0.14, 0.14]
x_cols = [0.05, 0.19, 0.33, 0.45, 0.59, 0.73]
y_debut = 0.88
# En-tête
for j, (col, x_c) in enumerate(zip(colonnes, x_cols)):
ax.text(x_c, y_debut, col, ha='left', va='center',
fontsize=10, fontweight='bold', color='#2c3e50',
transform=ax.transAxes)
ax.axhline(y=y_debut - 0.05, xmin=0.02, xmax=0.98, color='#cccccc',
linewidth=1, transform=ax.transAxes)
for i, (synt, nom, var, cmd, esc, glob, c) in enumerate(types):
y = y_debut - 0.13 - i * 0.16
# Fond coloré
fond = patches.FancyBboxPatch(
(0.03, y - 0.06), 0.94, 0.13,
boxstyle="round,pad=0.01", linewidth=1.5,
edgecolor=c, facecolor=(*c[:3], 0.12),
transform=ax.transAxes
)
ax.add_patch(fond)
valeurs = [synt, nom, var, cmd, esc, glob]
for j, (val, x_c) in enumerate(zip(valeurs, x_cols)):
couleur_texte = c if j <= 1 else ('#27ae60' if val == 'Oui' else ('#e74c3c' if val == 'Non' else '#e67e22'))
ax.text(x_c, y, val, ha='left', va='center',
fontsize=9.5, color=couleur_texte,
fontfamily='monospace' if j == 0 else 'sans-serif',
fontweight='bold' if j == 0 else 'normal',
transform=ax.transAxes)
# --- Exemples d'interpolation ---
ax2 = axes[0, 1]
ax2.axis('off')
ax2.set_title('Exemples : variable = "Alice"', fontsize=13, fontweight='bold')
exemples = [
('"Bonjour, $nom !"', '→ Bonjour, Alice !', couleurs['double']),
('"Date: $(date)"', '→ Date: ven. 15 mars', couleurs['double']),
('"$(( 2+3 ))"', '→ 5', couleurs['double']),
("'Bonjour, $nom !'", "→ Bonjour, $nom !", couleurs['simple']),
('$\'Tab:\\there\'', '→ Tab: here', couleurs['dollar']),
('$nom (sans guillemets)', '→ Alice (dangereux)', couleurs['aucun']),
]
for i, (expr, résultat, c) in enumerate(exemples):
y_base = 0.88 - i * 0.14
ax2.text(0.04, y_base, expr, ha='left', va='center',
fontsize=9.5, fontweight='bold', color=c,
fontfamily='monospace', transform=ax2.transAxes)
ax2.text(0.04, y_base - 0.065, résultat, ha='left', va='center',
fontsize=9, color='#555555', style='italic',
transform=ax2.transAxes)
ax2.axhline(y=y_base - 0.11, xmin=0.02, xmax=0.98, color='#eeeeee',
linewidth=0.8, transform=ax2.transAxes)
# --- Variables spéciales ---
ax3 = axes[1, 0]
ax3.axis('off')
ax3.set_title('Variables spéciales ($0, $@, $?, $$, …)', fontsize=13, fontweight='bold')
vars_spéciales = [
('$0', 'Nom du script', '#2980b9'),
('$1…$9', 'Arguments positionnels', '#2980b9'),
('$#', 'Nombre d\'arguments', '#27ae60'),
('$@', 'Tous les args (séparés)', '#27ae60'),
('$*', 'Tous les args (un mot)', '#e67e22'),
('$?', 'Code de retour', '#e74c3c'),
('$$', 'PID du shell', '#8e44ad'),
('$!', 'PID du dernier &', '#8e44ad'),
('$-', 'Flags du shell', '#95a5a6'),
('$_', 'Dernier argument', '#95a5a6'),
]
for i, (var, desc, c) in enumerate(vars_spéciales):
col = 0 if i < 5 else 1
row = i if i < 5 else i - 5
x_base = 0.04 + col * 0.5
y_base = 0.88 - row * 0.17
ax3.text(x_base, y_base, var, ha='left', va='center',
fontsize=11, fontweight='bold', color=c,
fontfamily='monospace', transform=ax3.transAxes)
ax3.text(x_base + 0.11, y_base, desc, ha='left', va='center',
fontsize=8.5, color='#555555', transform=ax3.transAxes)
# --- Opérations arithmétiques ---
ax4 = axes[1, 1]
ax4.axis('off')
ax4.set_title('Mécanismes arithmétiques', fontsize=13, fontweight='bold')
mécanismes = [
('$((expr))', 'Expansion — retourne le résultat', palette[0]),
('((expr))', 'Commande — code de retour (if/for)', palette[1]),
('let "expr"', 'Ancienne syntaxe (déconseillée)', palette[4]),
('bc', 'Virgule flottante et précision', palette[2]),
('awk BEGIN', 'Calculs flottants dans awk', palette[3]),
]
exemples_arith = [
'x=$((a*b + c))',
'if (( x > 10 )); then',
'let "x = a + b"',
'echo "scale=4; $x/$y" | bc',
'awk "BEGIN {printf \"%.2f\\n\", $x/$y}"',
]
for i, ((méca, desc, c), ex) in enumerate(zip(mécanismes, exemples_arith)):
y_base = 0.88 - i * 0.17
fond = patches.FancyBboxPatch(
(0.02, y_base - 0.07), 0.96, 0.15,
boxstyle="round,pad=0.01", linewidth=1.5,
edgecolor=c, facecolor=(*c[:3], 0.12),
transform=ax4.transAxes
)
ax4.add_patch(fond)
ax4.text(0.05, y_base + 0.025, méca, ha='left', va='center',
fontsize=10, fontweight='bold', color=c,
fontfamily='monospace', transform=ax4.transAxes)
ax4.text(0.38, y_base + 0.025, desc, ha='left', va='center',
fontsize=8.5, color='#555555', transform=ax4.transAxes)
ax4.text(0.05, y_base - 0.04, ex, ha='left', va='center',
fontsize=8, color='#888888', style='italic',
fontfamily='monospace', transform=ax4.transAxes)
plt.tight_layout()
plt.show()
Bonnes pratiques avec les variables#
Remarque 24
Quelques règles à respecter systématiquement pour écrire des scripts Bash sûrs et lisibles :
Toujours citer les variables :
"$variable"et non$variable. Les espaces et les caractères spéciaux dans les valeurs de variables peuvent causer des comportements inattendus.Utiliser
${variable}quand nécessaire : pour lever les ambiguïtés quand le nom de variable est suivi de caractères alphanumériques (${var}nameet non$varname).Préférer
$(commande)aux backticks : meilleure lisibilité, imbrication possible.Déclarer les constantes avec
declare -roureadonly: cela protège les valeurs critiques contre les modifications accidentelles.Utiliser des valeurs par défaut :
${variable:-valeur_par_défaut}évite les erreurs dues aux variables non définies quandset -uest actif.Nommage explicite : des noms de variables descriptifs (
chemin_fichier_logplutôt quef) améliorent considérablement la lisibilité.
Résumé#
Dans ce chapitre, nous avons exploré le système de variables de Bash dans sa totalité :
L”affectation ne tolère aucun espace autour du
=. Par convention, les variables locales sont en minuscules et les variables d’environnement en majuscules.echoest pratique mais peu portable ;printfest recommandé dans les scripts pour son contrôle précis du format de sortie.Les guillemets doubles permettent l’interpolation des variables et des substitutions de commandes tout en protégeant des espaces et du globbing. Les guillemets simples traitent tout littéralement. La syntaxe
$'...'permet les séquences d’échappement dans une chaîne littérale. L’absence de guillemets active le word splitting et le globbing — à éviter autour des variables.Les variables d’environnement sont exportées avec
exportet transmises aux processus enfants.PATH,HOME,USER,SHELLetLANGsont parmi les plus importantes.Les variables spéciales —
$0,$1…$#,$@,$*,$?,$$,$!— sont gérées automatiquement par le shell et essentielles pour tout script.La substitution de commandes
$(commande)insère la sortie d’une commande dans une expression.L”arithmétique entière s’effectue avec
$(( ))ou(( )). Les calculs en virgule flottante nécessitentbcouawk.declarepermet d’attribuer des types aux variables :-r(readonly),-i(entier),-l/-u(normalisation de casse),-a/-A(tableaux).
Dans le chapitre suivant, nous aborderons les structures de contrôle — conditions, boucles et ruptures de flux — qui permettent de construire des scripts avec une logique de branchement et d’itération.