Bash

Tags :
  • COURS
  • informatique
  • développement
  • bash
  • scripting
Auteurs :
  • Loïck Goupil-Hallay

Introduction

Le Bourne-Again Shell (Bash) est un interpréteur de commandes qui permet d'exécuter des scripts shell.
Il est le shell par défaut sur la plupart des systèmes Unix et Linux.

Ce langage de script est très utilisé pour automatiser des tâches, car il permet de manipuler des fichiers, des processus, des variables et d'effectuer des opérations logiques et arithmétiques. De plus, il est très extensible et permet d'utiliser des commandes système.

Il s'agit d'un langage interprété et non typé. Il est orienté ligne de commande et procédural.

Variables

Définition

Les variables en Bash sont déclarées sans type. Elles ont en réalité un type unique, qui est une chaîne de caractères.
Elles sont définies par une affectation de la forme nom_variable=valeur. Il ne doit pas y avoir d'espace avant ou après le signe =.
Pour supprimer une variable, on utilise la commande unset nom_variable.

Par convention, les noms de variables sont en majuscules, mais ce n'est pas une obligation.



# Déclaration d'une variable
point_faible="trop fort"

# Suppression d'une variable
unset point_faible


Utilisation

Pour accéder à la valeur d'une variable, on utilise le signe $ suivi du nom de la variable.
Une bonne pratique est d'entourer le nom de la variable d'accolades {} pour éviter les ambiguïtés.
Une autre bonne pratique est d'entourer le nom de la variable de guillemets "" pour éviter les problèmes de résolution de variables avec espace(s).

Attention

Les simples quotes ' permettent de définir une chaîne de caractères MAIS ne permettent pas de résoudre les variables.



# La commande echo affiche la valeur de la variable
echo $point_faible

# Utilisation des accolades
echo ${point_faible}

# Utilisation des guillemets pour éviter les problèmes d'espaces
echo "$point_faible"

# Combinaison des deux bonnes pratiques (on est sur de ne pas avoir de problème)
echo "${point_faible}"


Vérifier l'existence d'une variable

Pour vérifier si une variable est définie, on utilise simplement un test sur la variable.
On utilise les opérateurs -v pour vérifier si la variable est définie, -z pour vérifier si la variable est vide, -n pour vérifier si la variable est non vide.



# vérifier si la variable est définie
if [ -v point_faible ]; then
    echo "La variable est définie"
fi

# vérifier si la variable n'est pas définie
if [ ! -v point_faible ]; then
    echo "La variable n'est pas définie"
fi

# vérifier si la variable n'est pas définie ou est vide
if [ -z "${point_faible}" ]; then
    echo "La variable est vide"
fi

# vérifier si la variable est définie et n'est pas vide
if [ -n "${point_faible}" ]; then
    echo "La variable existe et n'est pas vide"
fi


Variables spéciales

Il existe des variables spéciales qui sont automatiquement définies par le shell. Elles ne peuvent pas être modifiées manuellement.
Voici quelques exemples :

Variable Description
$0 Nom du script
$1, $2, ... Paramètres passés au script
$# Nombre de paramètres passés au script
$? Code de retour de la dernière commande exécutée (0 si succès, autre valeur sinon)
$@ Liste des paramètres passés au script
$* Liste des paramètres passés au script
$- Options du shell
$_ Dernier argument du dernier processus lancé
$$ PID du script
$! PID du dernier processus lancé en arrière-plan



```bash
# Affiche le nom du script
echo $0

# Affiche le premier paramètre passé au script
echo $1

# Affiche le nombre de paramètres passés au script
echo $#

# Affiche le code de retour de la dernière commande exécutée
echo $?


Variables locales / environnement

Les variables en Bash peuvent être locales ou globales.\

Pour définir une variable globale, on utilise la commande export nom_variable=valeur.
Pour définir une variable locale, on utilise simplement une affectation nom_variable=valeur.



# Déclaration d'une variable globale
export point_faible="trop fort"

# Déclaration d'une variable locale
point_faible="trop fort"


Opérations logiques / arithmétiques

Syntaxe

La syntaxe des tests conditionnels en Bash est simple:

Opérateurs de test

Voici quelques opérateurs de test courants:

Description Syntaxe [ ] Syntaxe [[ ]]
Test d'égalité -eq ==
Test de non égalité -ne !=
Test d'infériorité -lt <
Test d'infériorité ou égalité -le <=
Test de supériorité -gt >
Test de supériorité ou égalité -ge >=
Test de chaîne vide -z == ""
Test de chaîne non vide -n != ""
Test d'existence d'un chemin -e -e
Test de fichier -f -f
Test de répertoire -d -d
Test de lecture -r -r
Test d'écriture -w -w
Test d'exécution -x -x
ET logique -a &&
OU logique -o ||
NON logique ! !
OU exclusif ^ ^


# Test d'égalité
test 1 -eq 1
[ 1 -eq 1 ]
[[ 1 -eq 1 ]]

# Test de variable vide
test -z ""
[ -z "" ]
[[ -z "" ]]

# Test de fichier
test -f fichier.txt
[ -f fichier.txt ]
[[ -f fichier.txt ]]

# test de ET logique
test 1 -eq 1 -a 2 -eq 2
[ 1 -eq 1 -a 2 -eq 2 ]
[[ 1 -eq 1 && 2 -eq 2 ]]


Syntaxe if/elif/else

On peut ensuite utiliser des instructions conditionnelles comme if, elif, else, fi pour exécuter des blocs de code en fonction des résultats des tests.



# Test d'égalité simple
if [[ "${point_faible}" == "trop fort" ]]; then
    echo "Vous êtes trop fort"
fi

# Test d'égalité avec else
if [[ "${point_faible}" == "trop fort" ]]; then
    echo "Vous êtes trop fort"
else
    echo "Vous n'êtes pas trop fort"
fi

# Test d'égalité avec elif
if [[ "${point_faible}" == "trop fort" ]]; then
    echo "Vous êtes trop fort"
elif [[ "${point_faible}" == "trop faible" ]]; then
    echo "Vous êtes trop faible"
else
    echo "Je ne m'attendais pas à ça"
fi


Opérations arithmétiques

Pour effectuer des opérations arithmétiques en Bash, on utilise l'expansion arithmétique (( )).
On peut utiliser les opérateurs arithmétiques classiques (+, -, *, /, %, **) et les opérateurs de comparaison (<, <=, >, >=, ==, !=).

Il est possible d'utiliser des variables dans les opérations arithmétiques.
Il est possible de combiner plusieurs opérations arithmétiques dans une même expression.

Attention

  • Les opérateurs de comparaison ne sont pas les mêmes que ceux utilisés dans les tests conditionnels.
  • Les opérations ne s'effectuent qu'entre des nombres entiers et renvoient toujours un nombre entier.


# Addition
echo $((1 + 1))

# Comparaison
if ((1 < 2)); then
    echo "1 est inférieur à 2"
fi


Redirections

Les redirections en Bash permettent de rediriger la sortie standard, la sortie d'erreur et l'entrée standard d'une commande.
Il existe plusieurs types de redirections:

Symbole Description
> ou 1> Redirige la sortie standard vers un fichier (écrase le fichier s'il existe)
>> ou 1>> Redirige la sortie standard vers un fichier (ajoute à la fin du fichier s'il existe)
2> Redirige la sortie d'erreur vers un fichier
2>> Redirige la sortie d'erreur vers un fichier (ajoute à la fin du fichier s'il existe)
&> ou 1>&2 Redirige la sortie standard et la sortie d'erreur vers un fichier
&>> ou 1>>&2 Redirige la sortie standard et la sortie d'erreur vers un fichier (ajoute à la fin du fichier s'il existe)
< ou 0< Redirige l'entrée standard depuis un fichier
<< ou 0<< Redirige l'entrée standard depuis un texte
| Redirige la sortie standard d'une commande vers l'entrée standard d'une autre commande


# Redirection de la sortie standard
echo "Hello" > fichier.txt

# Redirection de la sortie standard (ajout)
echo "World" >> fichier.txt

# Redirection de la sortie d'erreur
echo "Erreur" 2> erreur.txt

# Redirection de la sortie standard et de la sortie d'erreur
echo "Hello" &> fichier.txt

# Redirection de l'entrée standard
cat < fichier.txt

# Redirection de la sortie standard d'une commande vers l'entrée standard d'une autre commande
cat fichier.txt | grep "Hello"


Boucles

Arrays

Les tableaux en Bash sont des variables qui peuvent contenir plusieurs valeurs.
Ils sont déclarés par une affectation de la forme nom_tableau=(valeur1 valeur2 ...).




# Déclaration d'un tableau
nombres=(un deux trois quatre cinq)

# Accès à une valeur du tableau
echo ${nombres[0]} # affiche "un"

# Accès à toutes les valeurs du tableau
echo ${nombres[*]} # affiche "un deux trois quatre cinq"

# Affiche la taille du tableau
echo ${#nombres[@]} # affiche "5"

# Ajout d'une valeur à la fin du tableau
nombres+=(six)

# Suppression d'une valeur du tableau
unset nombres[0]

# Tester si une valeur est dans le tableau
if [[ " ${nombres[*]} " == *" trois "* ]]; then
    echo "La valeur trois est dans le tableau"
fi

# Tester si une valeur n'est pas dans le tableau
if [[ " ${nombres[*]} " != *" sept "* ]]; then
    echo "La valeur sept n'est pas dans le tableau"
fi

#Tester si le tableau est vide
if [[ ${#nombres[@]} -eq 0 ]]; then
    echo "Le tableau est vide"
fi



Boucle for

La boucle for permet de répéter un bloc de code pour chaque élément d'un tableau.
La syntaxe est for element in tableau; do ...; done.




# Boucle for
for element in "${nombres[@]}"; do
    echo ${element}
done

# Boucle for avec index
for ((i=0; i<${#nombres[@]}; i++)); do
    echo ${nombres[$i]}
done


Boucle while

La boucle while permet de répéter un bloc de code tant qu'une condition est vraie.
La syntaxe est while condition; do ...; done.



# Boucle while
i=0
while [[ $i -lt ${#nombres[@]} ]]; do
    echo ${nombres[$i]}
    ((i++))
done



Boucle until

La boucle until permet de répéter un bloc de code tant qu'une condition est fausse.
La syntaxe est until condition; do ...; done.




# Boucle until
i=0
until [[ $i -ge ${#nombres[@]} ]]; do
    echo ${nombres[$i]}
    ((i++))
done



Fonctions

Les fonctions en Bash sont déclarées par une affectation de la forme nom_fonction() { ... }.
Pour appeler une fonction, on utilise simplement son nom sans parenthèses cette fois.

On peut passer des paramètres à une fonction en les passant directement après le nom de la fonction.
Pour accéder aux paramètres passés à une fonction, on utilise les variables $1, $2, ...
Pour accéder à tous les paramètres passés à une fonction, on utilise l'opérateur $@.

Les fonctions peuvent retourner une valeur en utilisant la commande return.

Attention

  • La valeur de retour d'une fonction est un nombre entier compris entre 0 et 255.
  • Il est stocké dans la variable $?.
  • La valeur de retour par défaut d'une fonction est 0 si la commande return n'est pas utilisée.
  • La valeur de retour est supposée être un code d'erreur, pas une véritable valeur de retour.


# Déclaration d'une fonction
function dire_bonjour() {
    echo "Bonjour"
    return 0 # optionnel
}

# Appel de la fonction
dire_bonjour

# Déclaration d'une fonction avec paramètres
function dire_bonjour_a() {
    if [[ $# -neq 1 ]]; then
        echo "Usage: dire_bonjour_a nom"
        return 1
    fi
    echo "Bonjour $1"
    return 0 # optionnel
}

# Appel de la fonction avec paramètres
dire_bonjour_a "John Doe"

# Stockage de la sortie standard d'une fonction dans une variable
message=$(dire_bonjour_a "John Doe")
echo $message # affiche "Bonjour John Doe"


Exercices

Bonnes pratiques

  • Lint: Utiliser un linter tel que ShellCheck pour vérifier la syntaxe du code.
  • Indentation: Indenter le code pour le rendre plus lisible.
  • Commentaires: Ajouter des commentaires pour expliquer le code.
  • Noms de variables: Utiliser des noms de variables explicites.
  • Guillemets: Utiliser des guillemets pour éviter les problèmes d'espaces.

Pour aller plus loin dans la pratique de Bash, vous pouvez vous exercer sur le track Exercism: Bash.