5.1 Du terminal au script Bash
5.1.1 Qu’est-ce qu’un script Bash ?
Bash est le shell que nous utilisons pour lancer des commandes. Il fournit aussi un langage permettant d’écrire ces commandes dans un fichier et de les organiser.
Un script Bash est donc simplement un fichier texte contenant des instructions Bash. L’intérêt est de pouvoir rejouer automatiquement une suite d’actions au lieu de les saisir manuellement à chaque fois.
5.1.2 Le shebang : quel interpréteur doit lire le fichier ?
Lorsque nous voulons exécuter directement un script, Linux doit savoir quel programme doit interpréter son contenu. On place pour cela un shebang sur la première ligne :
#!/bin/bash
Cette ligne indique que le script doit être interprété par Bash. Le principe n’est pas propre à Bash : un script Python peut par exemple commencer par #!/usr/bin/env python3.
5.1.3 Créer un premier script
Créons un fichier script.sh avec Nano :
nano script.sh
Ajoutons le shebang puis une commande qui liste le contenu de la racine / :
#!/bin/bash
ls /
Nous avons maintenant une suite de commandes enregistrée dans un fichier.
5.1.4 Deux façons d’exécuter le script
Première possibilité : demander explicitement à Bash de lire le fichier :
bash script.sh
Ici, nous lançons bash et lui donnons script.sh comme fichier à interpréter.
Deuxième possibilité : exécuter directement le fichier :
./script.sh
Cette fois, le système tente d’exécuter script.sh lui-même. Le shebang lui indique alors d’utiliser Bash. Mais le fichier doit posséder le droit d’exécution x, notion vue au chapitre précédent.
chmod +x script.sh
./script.sh
./script.sh si le droit d’exécution n’est pas accordé.5.2 Mémoriser et réutiliser des valeurs
5.2.1 Commenter le code
Une ligne commençant par # est un commentaire : elle sert à documenter le script et n’est pas exécutée.
# Cette ligne explique ce que fait le script
5.2.2 Créer une variable
Une variable associe un nom à une valeur. L’affectation se fait avec = :
my_variable=hello
Il ne faut pas mettre d’espace autour du signe =.
Si nous écrivons :
echo my_variable
Bash affiche le texte my_variable. Pour demander le contenu de la variable, on préfixe son nom avec $ :
echo $my_variable
my_variable est le nom ; $my_variable demande à Bash de remplacer ce nom par sa valeur.Les variables Bash ne sont pas déclarées avec un type. Leur contenu est souvent manipulé comme du texte, mais certaines valeurs peuvent aussi être utilisées dans des calculs et des comparaisons.
5.2.3 Les guillemets : protéger ou interpréter du texte
Une affectation telle que :
my_variable=hello world
pose problème car l’espace sépare les éléments de la ligne. Pour conserver toute la phrase comme une seule valeur :
my_variable="hello world"
echo $my_variable
Les guillemets simples et doubles n’ont pas le même comportement :
echo 'the content of my variable is $my_variable'
echo "the content of my variable is $my_variable"
| Écriture | Comportement |
|---|---|
'...' | Le contenu est conservé littéralement : $my_variable reste du texte. |
"..." | Bash remplace $my_variable par sa valeur. |
5.2.4 Récupérer le résultat d’une commande
Un script a souvent besoin de stocker non pas une valeur écrite à l’avance, mais le résultat d’une commande. Le cours présente l’ancienne syntaxe avec apostrophes inversées :
my_variable=`ls -l`
echo $my_variable
La syntaxe moderne recommandée est :
my_variable=$(ls -l)
echo $my_variable
$(...) demande à Bash d’exécuter la commande située à l’intérieur puis de substituer son résultat.
5.2.5 Faire des calculs
Le cours utilise let pour effectuer des opérations arithmétiques :
let "a=1"
let b=2
let "c=b"
let "d = a + b * c"
echo $d
On retrouve notamment les opérateurs +, -, *, / et **.
5.3 Stocker plusieurs valeurs : les tableaux
5.3.1 Créer et lire un tableau
Une variable contient une valeur. Un tableau (array) permet d’en stocker plusieurs :
my_array=(hello world)
Chaque valeur possède un indice. Comme dans de nombreux langages, le premier indice est 0 :
echo ${my_array[0]}
5.3.2 Modifier et ajouter des éléments
my_array[0]=Hi
echo ${my_array[0]}
Pour afficher toutes les valeurs :
echo ${my_array[*]}
Les indices n’ont pas besoin de se suivre :
my_array[2]=or
my_array[4]=hello
my_array[1000]=world
echo ${my_array[*]}
5.3.3 Connaître les indices et le nombre d’éléments
echo ${!my_array[*]} # indices présents
echo ${#my_array[*]} # nombre d'éléments
5.4 Faire prendre des décisions au script
5.4.1 La structure if / then / fi
Un script devient réellement utile lorsqu’il peut adapter son comportement. La structure if exécute un bloc seulement si une condition est vraie :
prenom="Daniel"
if [ "$prenom" = "Daniel" ]
then
echo "Salut Daniel !"
fi
On peut lire cette structure ainsi : si la condition est vraie, alors exécuter le bloc, puis terminer le if.
5.4.2 Ajouter else et elif
else permet de définir ce qu’il faut faire lorsque la condition est fausse :
prenom="Daniel"
if [ "$prenom" = "Daniel" ]; then
echo "Salut Daniel !"
else
echo "Bonjour $prenom !"
fi
elif permet de tester un autre cas avant d’arriver au else :
prenom="Diane"
if [ "$prenom" = "Daniel" ]
then
echo "Salut Daniel !"
elif [ "$prenom" = "Diane" ]
then
echo "Salut Diane"
else
echo "Bonjour $prenom !"
fi
5.4.3 Comparer du texte et des nombres
| Test | Signification |
|---|---|
$var1 = $var2 | égalité de chaînes de caractères |
$var1 != $var2 | inégalité de chaînes de caractères |
-z $variable | chaîne vide |
-n $variable | chaîne non vide |
$var1 -eq $var2 | égalité numérique |
$var1 -ne $var2 | inégalité numérique |
$var1 -gt $var2 | var1 > var2 |
$var1 -lt $var2 | var1 < var2 |
$var1 -ge $var2 | var1 >= var2 |
$var1 -le $var2 | var1 <= var2 |
5.4.4 Combiner plusieurs conditions
&& signifie ET : les deux conditions doivent être vraies. || signifie OU : au moins une condition doit être vraie.
prenom="Diane"
nom="Datascientest"
if [[ $prenom == "Daniel" && $nom == "Datascientest" ]]
then
echo "Bonjour Daniel Data"
else
echo "Bonjour $prenom $nom"
fi
5.4.5 [ ], [[ ]] et (( )) : quelle forme utiliser ?
En Bash, une condition peut être écrite de plusieurs façons. Elles se ressemblent, mais elles n'ont pas exactement le même rôle. [ ... ] est la forme historique et portable issue de la commande test. [[ ... ]] est une construction plus moderne du shell Bash (et de quelques shells proches), plus sûre et plus expressive. Pour les calculs et comparaisons purement numériques, Bash possède aussi (( ... )).
| Forme | À privilégier pour | Pourquoi |
|---|---|---|
[ ... ] | Scripts devant rester compatibles POSIX, tests simples de fichiers, chaînes ou nombres | Très largement portable entre les shells, mais demande davantage de précautions avec les variables et les opérateurs. |
[[ ... ]] | Scripts Bash : chaînes, fichiers et conditions composées | Syntaxe Bash plus robuste : pas de découpage en mots ni d'expansion de jokers sur les variables ; && et || s'intègrent naturellement. |
(( ... )) | Entiers et expressions arithmétiques en Bash | Permet d'écrire les comparaisons numériques avec les opérateurs habituels <, >, ==, <=, etc. |
#!/bin/bash), utilisez généralement [[ ... ]] pour tester du texte ou des fichiers, et (( ... )) pour de l'arithmétique. Utilisez [ ... ] lorsque la compatibilité avec des shells POSIX est recherchée.Chaînes de caractères
[ "$nom" = "Axel" ]
[[ $nom == "Axel" ]]
Les deux formes savent comparer des chaînes. Avec [ ], entourer les variables de guillemets est une précaution importante. Avec [[ ]], Bash protège mieux les expansions de variables et permet aussi des comparaisons plus riches, notamment avec des motifs.
Fichiers et répertoires
| Test | Signification |
|---|---|
-e chemin | le chemin existe |
-f chemin | c'est un fichier ordinaire |
-d chemin | c'est un répertoire |
-r chemin | il est lisible |
-w chemin | il est inscriptible |
-x chemin | il est exécutable |
Ces opérateurs fonctionnent avec [ ] comme avec [[ ]]. Dans un script Bash, [[ -f $fichier ]] est généralement la forme la plus confortable ; dans un script POSIX, on utilisera plutôt [ -f "$fichier" ].
Nombres entiers
[ "$age" -ge 18 ]
[[ $age -ge 18 ]]
(( age >= 18 ))
[ ] et [[ ]] utilisent les opérateurs numériques historiques -eq, -ne, -lt, -le, -gt et -ge. En Bash, (( )) est souvent plus lisible pour les nombres car il utilise directement les opérateurs arithmétiques habituels.
[ ... ], < et > ne doivent pas être utilisés comme s'ils étaient des comparateurs numériques. Pour des entiers, utilisez -lt/-gt ou, en Bash, la forme arithmétique (( ... )).5.5 Répéter des actions avec des boucles
5.5.1 while : répéter tant qu’une condition est vraie
let i=0
while [ $i -lt 10 ]
do
let "i=i+1"
done
echo $i
La boucle teste i < 10. Tant que cette condition est vraie, elle augmente i de 1 puis recommence. Lorsque la condition devient fausse, le script sort de la boucle.
5.5.2 for : parcourir une série de valeurs
for x in '1st iteration' '2nd iteration' '3rd iteration'
do
echo $x
done
À chaque tour, x reçoit la valeur suivante de la liste.
5.5.3 seq : générer une suite d’entiers
La commande seq génère une suite d’entiers entre une valeur de départ et une valeur de fin :
seq 3 22
Elle peut donc fournir facilement une série de nombres à traiter dans une boucle.
5.6 Regrouper du code avec des fonctions
5.6.1 Définir une fonction
Une fonction permet de donner un nom à un bloc d’instructions afin de pouvoir l’appeler lorsque nous en avons besoin. Le cours présente deux syntaxes :
my_function () {
echo "Nous pouvons faire quelque chose ici"
}
ou :
function my_function {
echo "Nous pouvons faire quelque chose ici"
}
5.6.2 Passer des arguments à une fonction
Les arguments reçus par une fonction sont accessibles par leur position : $1 pour le premier, $2 pour le deuxième, etc.
function my_function {
echo "Premier argument"
echo $1
echo "Second argument"
echo $2
}
Pour appeler la fonction :
my_function "Daniel" "24"
Dans cet appel, Daniel devient $1 et 24 devient $2.
5.6.3 Produire une valeur et la réutiliser
En Bash, une fonction ne reçoit pas des paramètres nommés entre parenthèses comme en JavaScript. Elle récupère ses arguments avec $1, $2, $3, etc.
Lorsqu’une fonction doit produire une donnée, elle l’écrit généralement sur sa sortie standard avec echo. Une autre fonction peut ensuite récupérer cette sortie avec $(...).
# Première forme : le mot-clé "function" est autorisé,
# mais il n'est pas obligatoire en Bash.
function add {
local x=$1
local y=$2
# Cette fonction ne produit que le résultat de l'addition.
echo $((x + y))
}
# Deuxième forme, sans le mot-clé "function".
added_to() {
local x=$1
local y=$2
local who=$3
echo "$who retourne $(add "$x" "$y")"
}
message=$(added_to 4 5 "Axel")
echo "$message"
Résultat :
Axel retourne 9
Le déroulement est le suivant :
added_to 4 5 "Axel"appelle la fonction extérieure.$(add "$x" "$y")appelleaddet récupère uniquement9.added_toconstruit la chaîneAxel retourne 9.$(added_to ...)place cette chaîne dans la variablemessage.
function add { ... } utilise le mot-clé facultatif function, tandis que add() { ... } utilise les parenthèses vides. Dans les deux cas, les arguments sont accessibles avec $1, $2, etc.echo et return ne jouent pas le même rôle : echo produit une donnée récupérable avec $(...). return renvoie seulement un code de fin compris entre 0 et 255 : 0 signifie généralement succès et une autre valeur signale une erreur.5.6.4 Le point-virgule
Le point-virgule ; sépare plusieurs commandes placées sur une même ligne. Il n’est généralement pas nécessaire lorsque chaque commande possède sa propre ligne.
echo "Bonjour"; echo "Au revoir"
add() { local x=$1; local y=$2; echo $((x + y)); }
Dans la fonction écrite sur une seule ligne, chaque ; termine une commande. Le dernier est nécessaire avant l’accolade fermante }.
5.7 Le chemin logique d’un script Bash
| Besoin | Outil Bash | Rôle |
|---|---|---|
| Indiquer comment exécuter le fichier | #!/bin/bash | Choisir Bash comme interpréteur. |
| Exécuter directement le fichier | chmod +x puis ./script.sh | Donner puis utiliser le droit d’exécution. |
| Mémoriser une valeur | variable | Réutiliser une donnée plus tard. |
| Récupérer une commande | $(commande) | Stocker ou réutiliser sa sortie. |
| Stocker plusieurs valeurs | tableau | Regrouper plusieurs éléments. |
| Choisir une action | if / elif / else | Adapter le comportement du script. |
| Répéter | while, for | Automatiser une action répétitive. |
| Réutiliser un bloc | fonction | Structurer et éviter de répéter le code. |
| Récupérer la donnée d’une fonction | $(fonction arguments) | Capturer ce que la fonction écrit avec echo. |
| Signaler succès ou erreur | return 0 ou autre code | Renvoyer le code de fin de la fonction. |