Chapitre 7 et 8 - cegepmv/420-113 GitHub Wiki

Programmation bash

Dans cette section, nous allons voir quels sont les bases de la programmation "shell" avec l'interpréteur de commandes bash.

Dans les systèmes linux, on peut créer des programmes pour organiser l'exécution de toutes les commandes qu'on a vues jusqu'ici. Le programme bash le plus simple qu'on peut imaginer est un fichier dans lequel on met une série de commandes linux, une par ligne. Les programmes les plus complexes utilisent (comme n'importe quel langage de programmation) des variables, des conditions ("if") et des boucles ("while" ou "for"). D'ailleurs, plusieurs commandes de linux, par exemple gunzip, adduser et which sont en réalité des programmes écrits en bash.

Par exemple, voici un programme simple qui supprime tout le contenu d'un répertoire et y crée 2 fichiers:

echo "Supprimer le contenu"
rm -r /home/info/travail/
echo "Créer les répertoires et les fichiers"
mkdir -p /home/info/travail/projet
touch /home/info/travail/fichier1.txt
echo "allo" > /home/info/travail/fichier2.txt

Lancer un programme

Il y a deux manières d'exécuter un programme bash.

La première consiste simplement à appeler l'interpréteur en lui passant le fichier du programme en argument:

info@debian:~$ bash monProgramme.sh

La deuxième consiste à ajouter #!/bin/bash à la première ligne du fichier puis lui donner les permissions d'exécution avec la commande chmod. Ensuite on peut appeler le programme par son nom, comme suit:

info@debian:~$ ./monProgramme.sh

Pour appeler le programme sans avoir à le précéder de ./, il suffit de le déplacer dans un des répertoires du PATH, par exemple /usr/local/bin.

Variables

Affectation

L'opérateur = sert à donner une valeur à une variable. Lorsqu'on souhaite lire cette valeur, il faudra préfixer la variable par $:

info@debian:~$ a=10
info@debian:~$ echo $a
10

Concaténation

Toutes les variables sont des chaînes de caractères dans bash: il est donc facile de les concaténer ou des les intégrer dans une chaîne de caractères:

info@debian:~$ a=bonjour
info@debian:~$ b=vous
info@debian:~$ echo $a $b
bonjour vous
info@debian:~$ echo "$a tout le monde"
bonjour tout le monde

Valeurs numériques

Si on souhaite faire des opérations arithmétiques sur des variables numériques, il faut les inclure dans des doubles parenthèses:

info@debian:~$ a=10
info@debian:~$ b=10
info@debian:~$ echo $a+$b
10+10
info@debian:~$ echo $((a+b))
20

Résultats de commandes

Il est possible de donner le résultat d'une commande comme valeur à une variable. Pour ce faire on doit mettre la commande entre parenthèses comme suit:

info@debian:~$ liste=$(ls)
info@debian:~$ echo $liste
Bureau cmd.sh Documents exemple.sh Images Modèles Musique Public Téléchargements travail Vidéos
info@debian:~$ liste=$(ls |grep "sh")
info@debian:~$ echo $liste
cmd.sh exemple.sh

Valeurs saisies par l'utilisateur

La commande read permet de stocker dans une variable la chaîne de caractères entrée par l'utilisateur. Par exemple:

info@debian:~$ read a
ceci est une phrase
info@debian:~$ echo $a
ceci est une phrase

Lire plusieurs valeurs simultanément

La commande read peut prendre plusieurs entrées simultanément.

info@debian:~$ echo "Fournier Maxime" > nomComplet.txt
info@debian:~$ read nom prenom < nomComplet.txt
info@debian:~$ echo $prenom $nom
Maxime Fournier

Conditions

Les structures conditionnelles doivent avoir la syntaxe suivante:

if [ CONDITION ](/cegepmv/420-113/wiki/-CONDITION-); then
    EXPRESSION
fi

Attention, les espaces entre [ et ](/cegepmv/420-113/wiki/-et-) et la condition sont importants!

Il est évidemment possible d'utiliser les instructions else ou elif.

#!/bin/bash

echo "Entrez un mot:"
read mot1
echo "Un autre:"
read mot2

if [ $mot1 = $mot2 ](/cegepmv/420-113/wiki/-$mot1-=-$mot2-); then
        echo "Les deux mots sont identiques"
else
        echo "Les deux mots sont différents"
fi

Opérateurs de comparaison

L'opérateur = dans l'exemple précédent permet seulement la comparaison entre deux chaînes de caractères. Lorsqu'on veut vérifier si deux nombres sont égaux, il faut utiliser -eq. Le tableau suivant contient la liste des opérateurs de compraison qu'on peut utiliser dans bash.

Opérateur Vrai si...
= deux chaînes de caractères sont identiques
!= deux chaînes de caractères sont différentes
< la première chaîne précède la deuxième dans l'ordre alphabétique
> la première chaîne suit la deuxième dans l'ordre alphabétique
-eq les deux nombres sont égaux
-ne les deux nombres sont différents
-gt le premier nombre est supérieur au deuxième
-ge le premier nombre est supérieur ou égal au deuxième
-lt le premier nombre est inférieur au deuxième
-le le premier nombre est inférieur ou égal au deuxième

REMARQUE: bash est généralement limité aux nombres entiers: il ne permet pas de manipuler des nombres décimaux de façon simple. Lorsque vous souhaitez faire une programme qui traite des nombres décimaux, il est préférable d'utiliser un autre langage de programmation!

Tests

Dans les expressions conditionnelles on peut aussi utiliser des opérateurs qui ne prennent qu'un seul terme (aussi appelés "opérateurs unaires"). Ceux-ci permettent de tester certaines conditions et valeurs de variables.

Par exemple dans le code suivant, on utilise -f pour vérifier si un fichier avec le nom spécifié existe avant de le supprimer (ceci permet d'éviter l'erreur qui surviendra si on tente de supprimer un fichier inexistant).

#!/bin/bash

fichier=/home/info/document.txt
if [ -f $fichier ](/cegepmv/420-113/wiki/--f-$fichier-); then
        rm $fichier
fi

Les opérateurs unaires les plus courants sont les suivants:

Opérateur Vrai si la variable...
-z est nulle / vide
-n contient une chaîne de caractères
-f désigne un fichier
-d désigne un répertoire
-e désigne un élément qui existe dans le système de fichiers (fichier, répertoire, lien symbolique, stockage, etc.)

Opérateurs logiques

Dans toute expression conditionnelle il est possible d'enchaîner plusieurs conditions avec les opérateurs logiques de conjonction (ET logique) et de disjonction (OU logique), et aussi d'inverser la valeur de vérité d'une expression avec l'opérateur de négation (NON logique):

#!/bin/bash

fichier=/home/info/abc
if [ ! -f $fichier ](/cegepmv/420-113/wiki/-!--f-$fichier-); then
        echo "Il n'y a pas de fichier nommé $fichier"
fi

Dans l'exemple suivant on vérifie si une des deux variables est vide:

#!/bin/bash

echo "Entrez un mot:"
read mot1
echo "Un autre:"
read mot2

if [ -z $mot1 ](/cegepmv/420-113/wiki/|--z-$mot2-); then
        echo "Vous avez oublié au moins un mot"
fi

Boucles

Les boucles en bash sont, comme dans la plupart des langages de programmation, de deux types: il y a les boucles while et les boucles for. Les contextes d'utilisation de chacune sont différents.

while

Les boucles while doivent avoir la syntaxe suivante:

while [ CONDITION ](/cegepmv/420-113/wiki/-CONDITION-); do
    EXPRESSION
done

Le cas le plus simple est celui d'une boucle basée sur un compteur. Dans l'exemple suivant, on affiche la variable $i tant que sa valeur est inférieure à 10:

i=0
while [ $i -lt 10 ](/cegepmv/420-113/wiki/-$i--lt-10-); do
    echo $i
    i=$(($i+1))
done

On peut également utiliser des boucles infinies "while-true" lorsqu'on veut arrêter une itération uniquement au moment où une donnée est reçue. Par exemple, dans le code suivant, on boucle jusqu'à ce que l'utilisateur entre le mot "stop":

while true; do
	read mot
	if [ $mot = "stop" ](/cegepmv/420-113/wiki/-$mot-=-"stop"-); then 
		echo $seq
		break	
	fi
	seq=$seq$mot
done

Le mot-clé break est ici utilisé pour sortir de la boucle.

Enfin, les boucles while sont souvent utilisées pour lire une à une les lignes d'un fichier. Dans ce cas on doit utiliser une redirection à partir d'un fichier avec l'opérateur <, comme suit:

while read ligne; do
	echo $ligne | wc -m
done < fichier.txt

Dans cet exemple la commande wc -m permet de compter le nombre de caractères (incluant les sauts de ligne) de chaque ligne du fichier.

for

On utilise for lorsque ce qui contrôle l'itération est un compteur ou des éléments d'une liste. La syntaxe est la suivante:

for ELEMENT in LISTE; do
    EXPRESSION
done

ELEMENT est une variable qui correspond à un élément de la liste différent pour chaque itération de la boucle.

La LISTE peut être exprimée de différentes manières. Dans un premier cas, elle peut être une simple énumération de valeurs:

for s in 12 13 ananas go tiger; do
	echo $s
done

Lorsque les valeurs font partie d'une séquence de nombres entiers, on peut la spécifier entre accolades comme suit:

for i in {10..30}; do
	echo $i
done

Aussi, toute commande qui retourne une liste d'éléments peut être utilisée dans ce contexte:

i=0
for f in $(ls); do
	i=$(($i+1))
        echo "$i. $f"
done

ATTENTION: for boucle sur tous les éléments séparés par des espaces. Donc si la commande retourne des lignes où plusieurs éléments sont séparés par des espaces, la variable f (dans l'exemple) ne correspondra pas à une ligne entière. Pour le constater, remplacez $(ls) par $(ls -l) dans l'exemple précédent.

Finalement, les boucles for peuvent itérer sur les éléments d'un répertoire. Dans l'exemple suivant, on affiche chacun des éléments du répertoire courant:

i=0
for elem in *; do
	echo $elem
done

Il est possible d'utiliser des expressions plus précises qu'un simple *, tant que cette expression peut être utilisée pour désigner des éléments du système de fichiers:

i=0
for elem in /home/info/Téléchargements/*.deb; do
	echo $elem
done

Arguments d'un programme

De la même façon que les commandes peuvent avoir des arguments, il est possible d'en passer à un script bash lorsqu'on le lance, comme suit:

info@debian:~$ ./prog.sh abc def

Dans cet exemple le programme est appelé avec deux arguments, "abc" et "def". Ceux-ci peuvent désigner des chaînes de caractères, des fichiers, des nombres et même être des variables. Les arguments peuvent être traités à l'intérieur du programme.

Des variables spéciales peuvent être utilisées dans le programme pour référer aux arguments passés. Le tableau suivant en fait la liste:

Variable Valeur
$0 Le nom du fichier du programme
$1, $2, etc. Le 1er, 2e, etc. argument du programme
$# Le nombre d'arguments passés au programme
$@ La liste des arguments du programme

Le programme suivant illustre comment ces variables peuvent être utilisées:

#!/bin/bash
echo "Le programme se nomme $0"
echo "Il a été appelé avec $# arguments"
echo "Le premier argument est $1"
echo "Le deuxième argument est $2"
echo "La liste complète des arguments est:"
for arg in $@; do
        echo "- $arg"
done