[4] Ligne de commande – Scripts Shell

Bonjour et bienvenus dans la quatrième parties consacré à la ligne de commandes Linux. Dans celle-ci, nous allons aborder ensemble le sujet du « scripts shell ».

Au programme :

Enchaîner plusieurs commandes en écrivant un script :
l’étape suivante consiste à savoir écrire un script, en commençant par choisir les outils appropriés.

Écrire un premier script shell :
nous allons créer ici notre tout premier script, qui consiste à afficher un simple texte à l’écran. Reste à savoir comme rendre le script exécutable et comment l’exécuter ?

Rendre un script paramétrable en utilisant des variables :
le comportement d’un script peut être modifié à loisir dès lors que l’on y intègre des valeurs qui peuvent être changées comme bon vous semble.

Exécuter des commandes suivant des conditions précises :
ici encore, nous allons voir comment le comportement d’un script peut différer selon certains paramètres.

Exécuter plusieurs fois une commande sans avoir à la ré-écrire :
les premiers scripts que l’on cherche à écrire concernent souvent le traitement par lots de fichiers.

images

01 ENCHAÎNER PLUSIEURS COMMANDES EN ÉCRIVANT UN SCRIPT .

Vous savez utiliser le shell depuis une console, exécuter des commandes simples ou même plus complexes à l’aide de redirections et de pipes ( | ), mais maintenant vous voulez enchaîner les commandes. Comment faire ? Écrire un script !

1 ) Mais, c’est quoi un script ?

Comme vous avez pu le lire dans les précédents articles, lorsque vous ouvrez une console ou lorsque vous ne vous connectez pas à Linux en mode graphique, vous aboutissez sur le shell de votre système et c’est là que vous pouvez taper et exécuter vos diverses commandes.

Ces commandes admettent généralement la même structure  : le nom de la commande suivi parfois d’options (précédées du caractère ou de ) et éventuellement d’arguments.
Par exemple, dans la commande ls aild /home, ls est la commande, aild représentent les options (aild est un raccourci pour a i l d ) et /home est l’argument.

Nous souhaitons maintenant exécuter un ensemble de commandes contenues dans un fichier. Il faudrait en plus rendre paramétrable l’exécution de code à l’aide, comme nous l’avons vu précédemment, d’options et de paramètres.

Par exemple, nous pourrions avoir une commande prepare_une_boisson permettant de préparer du café, du thé,ect. Le comportement général serait le même, à quelques différences près que nous pourrions régler en fournissant un paramètre à la commande : prepare_une_boisson cafe ou prepare_une_boisson the . Et pour préciser encore plus notre attente, nous pourrions ajouter des options : prepare_une_boisson cafe –type=fort ou prepare_une_boisson the –type=earl-grey.

En plus des commandes, le shell offre la possibilité d’utiliser des structures de contrôle qui permettront de gérer de manière précise l’exécution des commandes : nous pourrons ainsi exécuter de manière répétitive un certain nombre d’entre elles et éventuellement conditionner leur exécution.

La mise en œuvre de l’ensemble des mécanismes précédemment décrits permet de créer ce qu’on appel un script shell .

shell_scripting

2 ) Quels outils utiliser pour écrire mes scripts ?

Les scripts shell sont des fichiers textes tout ce qu’il y a de plus classique. Pour créer un fichier et y insérer du texte, on a deux possibilités :

1 : La méthode « geek », tout en ligne de commandes :

~$ echo « Contenu de mon fichier texte » > fichier.txt

Ici, vous créerez un fichier nommé fichier.txt et contenant la phrase « Contenu de mon fichier texte » .Si vous souhaitez ajouter du texte, il faudra le concaténer au contenu précédent :

~$ echo « Suite de mon fichier » >> fichier.txt

1.jpg

Pour lire le contenu complet de votre fichier, vous aurez le choix entre la commande more ou la commande cat :

~$ more fichier.txt
Contenu de mon fichier texte
Suite de mon fichier

~$ cat fichier.txt
Contenu de mon fichier texte
Suite de mon fichier

2

Là où ça se corse, c’est pour modifier le contenu du fichier !
Sans utiliser des outils aussi sophistiqués que sed ou awk, vous devrez employer la commande tr permettant de rechercher dans une chaîne les occurrences d’une chaîne et de les remplacer par une autre chaîne :

~$ cat fichier.txt | tr « fichier » « petit fichier » > fichier.txt

Comme vous le voyez, cette ligne fait intervenir deux commandes (cat et tr), un pipe et une redirection… Pour frimer devant les filles quand on est au collège, ou pour faire « pro » dans les films grand public (voir la mythique scène de Jurassic Park : « It’s a Unix system…I know this »), c’est ce qu’il faut. Sinon, il faut reconnaître que c’est quand même un peu complexe pour pas grand chose ! De plus, le risque d’erreur est très élevé. On utilisera donc préférentiellement la méthode suivante.

2 : méthode dite « classique », l’utilisation d’un éditeur de texte :

Attention, si l’on parle ici d’éditeur de texte, il existe une différence avec les logiciels de traitement de texte. Un éditeur de texte est capable de lire et d’écrire du texte : chaque caractère visible (en dehors des espaces, tabulations et autres sauts à la ligne) sera visible dans le fichier. Dans un traitement de texte, des informations supplémentaires sont sauvegardées sous divers formats : police sélectionnée, taille de la police, style, ect.

Les éditeurs de texte sont conçus pour améliorer la rapidité d’écriture de lignes de codes. Pour cela, ils disposent d’une fonctionnalité de coloration syntaxique permettant d’afficher les « mots » de votre programme de différentes couleurs en fonction de leur catégorie (mot-clé, valeur numérique, opérateur arithmétique, ect) .

3

Il existe de très nombreux éditeurs de texte, plus ou moins évolués, disposant de plus ou moins de fonctionnalités. On distinguera deux catégories d’éditeurs :
► les éditeurs en mode console.
► les éditeurs en mode graphique.

Voici une liste non exhaustive de ces différents éditeurs, accompagnés de leur catégorie et d’une brève description :

Éditeurs graphiques :

gedit, kedit, nedit => Famille d’éditeurs graphiques très simples fournissant la coloration syntaxique, l’ouverture et l’enregistrement de fichiers et les copier-coller (le minimum nécessaire).

gvim => Version graphique de vim, avec l’ajout d’une barre d’outils, ect.

xmacs => Version graphique de emacs.

eclipse => Éditeur de texte « lourd » pouvant être amélioré par l’ajout d’extensions. Convient éventuellement au développement de code dans différents langages tels que Java ou C (et encore), mais certainement pas pour des scripts shell !

 ► Éditeurs en mode console :

nano => Éditeur simpliste mais qui fait son boulot .

vim => Amélioration de l’éditeur vi. Vim signifie « Vi IMproved », soit vi amélioré. Il est installé par défaut avec toute distribution Linux : quand plus rien ne fonctionne, il reste vi!
Éditeur entièrement paramétrable, améliorable par l’ajout d’extensions, contenant de nombreux raccourcis clavier permettant un développement rapide. Sa caractéristique principale est la possibilité de passer en trois modes distincts : commande (action), insertion (écriture) et visuel (sélection de code par exemple). Si je devais lui trouver un défaut, ça serait la difficulté à prendre en main lors des premiers lancement.

emacs => Équivalent de vim, développé par Richard Stallman. Chez les fanatiques, emacs est les concurrent et l’opposé de vim. Les fans d’emacs vont jusqu’à dire : « VI VI VI, le nombre de la bête ! »

Les critères de choix d’un éditeur sont propres à chacun et il est très difficile de dire qu’il vaut mieux en choisir un plutôt qu’un autre (même si vous pourrez rencontrer de très nombreux informaticiens qui vous vanteront leur éditeur, bien plus puissant et ergonomique que le vôtre !)

À titre personnel, j’utilise nano même si vim reste l’un des plus efficace bien qu’il faut accepter de passer par une longue phase d’apprentissage pour l’utiliser efficacement et il est jamais conseillé à des personnes souhaitant commencer à développer ou simplement écrire quelques scripts.

Pour un usage ponctuel, gedit, l’éditeur par défaut de l’environnement graphique GNOME, est largement suffisant ! Si vous utilisez un quelconque autre éditeur de texte régulièrement, vous maîtriserez son emploi et serez donc bien plus performant avec ce dernier, même s’il n’apparaît pas forcément comme étant le plus adapté… Continuez donc à l’utiliser !

02ÉCRIRE UN PREMIER SCRIPT SHELL .

Il faut un début à tout. Avant de se lancer dans l’écriture de scripts complexes, il vaut mieux être certain de savoir précisément ce que l’on fait. La tradition dans le monde de l’informatique est de créer un programme affichant un simple message « Hello World ! » (le fameux « Hello World ! » …). Nous ne dérogerons pas à la règle … mais nous l’adapterons.

helloworld

1 )  Comment exécuter un fichier script ?

Pour exécuter une commande shell, il existe deux alternatives :

La première méthode est aussi la moins pratique : il faut lancer un shell en lui donnant en paramètre le nom d’un fichier contenant des commandes à exécuter.
Une fois que vous aurez crée et enregistré votre script avec l’extension .sh, vous devez appeler la commande correspondant à votre shell, suivie du nom de votre script.

Supposons que nous utilisons le shell Bash et que notre script se nomme monScript.sh. La commande à exécuter sera alors :

~# bash monScript.sh

La seconde méthode consiste à indiquer directement dans le fichier quelle est la commande (le shell) qui permettra de l’interpréter. Cette solution est un tout petit peu plus longue à mettre en place (une ligne de plus à écrire), mais elle est bien plus pratique pour l’utilisateur. En effet, ce dernier n’aura qu’à écrire le nom de la commande pour l’exécuter.

Pour mettre en place cette solution, il faut indiquer sur la première ligne du fichier de script quel est l’interpréteur qui permettra d’exécuter les commandes des lignes suivantes. Cette ligne possède une syntaxe particulière : les caractères #! suivis du chemin absolu (depuis la racine) vers l’interpréteur.

Dans le cas du Bash, nous aurons comme première ligne du fichier monScript.sh :

#!/bin/bash

55-1

Toutefois, pour que le mécanisme fonctionne, vous devrez rendre ce script exécutable (attention à la gestion des droits utilisateurs (u), groupe (g) et autres (o)). Il faut utiliser la commande chmod pour modifier les droits d’un fichier en lecture (r), écriture (w) et exécution (x). Cette commande, que vous pourrez voir plus en détail dans un article suivant, peut être utilisée de deux manières que nous allons tester sur le script monScript.sh .

La première méthode consiste à garder les droits actuels du fichier et à ajouter ou à retirer des droits en fonction des utilisateurs :

~# chmod u+x monScript.sh; chmod o-rw monScript.sh; ls -al monScript.sh

5-2

Dans cet exemple, nous avons pris le fichier monScript.sh avec les droits qui lui avaient été affectés par défaut (si vous n’avez pas modifié le masque, ces droits sont lecture et écriture pour l’utilisateur et le groupe et seulement lecture pour les autres), puis nous avons ajouté le droit d’exécution pour l’utilisateur et retiré les droits de lecture et d’écriture pour les autres. Au final, les droits du fichier sont donc lecture, écriture et exécution pour l’utilisateur, lecture et écriture pour le groupe  et aucun droit pour les autres.

La seconde méthode consiste à indiquer sous forme de codage octal les droits de chaque groupe dans l’ordre utilisateur, groupe, puis autres. Un code octal commence par le chiffre 0, puis un chiffre en base 8 pour les droits de chaque groupe : 0 pour aucun droit, 1 droit d’exécution, 2 droit d’écriture, 4 droit de lecture, ou une combinaison de ces droits.

Une fois que vous aurez ajouté la ligne indiquant le programme capable d’interpréter votre script et que vous aurez donné les droits en exécution à votre fichier, il ne vous reste plus qu’à taper le nom de votre fichier dans un terminal pour celui-ci soit exécuté …

2 ) Premier script : « Hello GNU/LINUXIENS !« 

Nous allons maintenant pouvoir réaliser notre premier script shell.

Pour que l’exemple reste le plus simple possible, nous allons seulement utiliser la commande d’affichage echo. Cette commande admet pour paramètre une chaîne de caractères qu’elle imprimera sur le périphérique de sortie standard (par défaut, il s’agit de l’écran). Nous pouvons utiliser cette commande en shell interactif en tapant directement après le prompt :

~$ echo « Hello GNU/LINUXIENS ! »

6.jpg

Pour créer un script qui exécutera cette même commande, il faut ouvrir un fichier texte (que nous appellerons ici hello.sh) :

~# nano hello.sh

et y ajoutez-y ceci à l’intérieur :

#!/usr/bin/bash

# Nous allons afficher un message !
echo « Hello GNU/Linuxiens ! »

6-1

Les caractères  de la ligne 3 qui suivent le caractère # ne sont pas interprétés (sauf cas spécial du shebang de la première ligne). Ainsi la phrase de la troisième ligne constitue un commentaire permettant d’indiquer à un lecteur, éditeur (nous sommes dans l’open-source ! Ne l’oublions pas.) du fichier ce qu’on a souhaité réaliser.

On ne soulignera jamais assez l’importance des commentaires dans un code : le message permettra peut être d’aider un développeur qui veut améliorer votre script, ou plus simplement, il vous aidera vous ! En effet, si vous délaissez un script quelques temps, puis que vous y revenez pour corriger un bug ou y apporter une amélioration, vous serez heureux de retrouver ces petits messages vous indiquant ce que fait le code, pourquoi avoir choisi d’exécuter telle commande plutôt que telle autre. Et ne croyez pas qu’il faille laisser passer beaucoup de temps pour « oublier » la structure d’un code pour pouvoir le maintenir et augmenter sa durée de vie (un code in-maintenable n’évolue plus et il est voué à une mort certaine).

Notez que les commentaires ne commencent pas forcément une ligne. En ligne 4, nous aurions pu écrire :

echo « Hello GNU/Linuxiens ! » # Ceci est un commentaire

7

Les lignes vides ne sont pas interprétés non plus : utilisez-les pour aérer votre code et le rendre plus lisible en regroupant les lignes de même « fonction« . Comme dans un texte, vous aurez ainsi des « paragraphes » permettant de faciliter la lecture.

Pour tester le script, rendez votre fichier exécutable avec la commande chmod comme vu précédemment :

~# chmod u+x hello.sh

puis lancez votre script simplement à l’aide de la commande :

~# bash hello.sh

8

Bien sûr, tout ceci ne constitue que la base de l’élaboration des scripts, mais nous voyons que nous pouvons déjà enchaîner des commandes que nous tapions précédemment dans le shell : il suffit de créer un fichier et d’y écrire les commandes dans l’ordre dans lequel on souhaite qu’elles s’exécutent.

Par exemple, nous pouvons modifier notre exemple ou en créer un nouveau script que nous nommerons hello2.sh de manière à ce qu’il se déplace dans le répertoire home/votre_login/Documents et qu’il crée un fichier hello.txt contenant la phrase « Hello GNU/Linuxiens ! » :

#!/usr/bin/bash

# Déplacement dans le répertoire /home/votre_login/Documents
cd /home/LinuxFrench/Documents

# Création du fichier
echo « Hello GNU/Linuxiens ! » > hello.txt

# Affichage d’un message
echo « le fichier hello.txt a été crée… »

On vérifie :
(n’oubliez pas de rendre votre script exécutable!)

~# bash hello2.sh; ls /home/votre_login/Documents/hello.txt; cat /home/votre_login/Documents/hello.txt

910

0403RENDRE UN SCRIPT PARAMÉTRABLE EN UTILISANT DES VARIABLES .

Un script permet de placer des commandes dans un fichier et de les exécuter … Mais si l’on ne peut pas faire varier légèrement son comportement en changeant des valeurs comme des chaînes de caractères ou des nombres, l’intérêt est très limité. Heureusement pour nous, il existe les variables.

01 ) Qu’est-ce qu’une variable ?

Une variable n’est jamais qu’un espace réservé en mémoire dans lequel on peut écrire des données. Pour accéder plus simplement à cet espace, on lui donne un nom (utiliser une adresse du type 0x278faa0 est nettement moins pratique !). On peut voir une variable comme une boite sur laquelle on colle une étiquette portant un nom.

Si nous plaçons dans notre boite un carré de chocolat et que nous inscrivons sur l’étiquette « miam_miam« , nous pourrons dire « Tiens, je mangerais bien un miam_miam » et cela se traduira par « Tiens, je mangerais bien un carré de chocolat« . Le fait de modifier le contenu de la boite modifiera le sens de notre phrase. Si nous plaçons maintenant dans la boite un kiwi, la traduction donnera « Tiens, je mangerais bien un kiwi« . ainsi, nous pouvons décrire une seule fois notre action et le rendre paramétrable à l’aide d’une variable qui se nomme ici miam_miam.

Pour revenir dans un cadre un peu plus formel, une variable est définie par un identifiant (son nom) et une valeur (son contenu). Lorsque l’on définit une variable, on réserve un espace mémoire (par exemple 0x278faa0) et on lui associe un nom (par exemple miam_miam), puis on y stocke une valeur (le « carré de chocolat » de l’exemple précédent). Lorsque nous utiliserons notre variable, l’interpréteur lira le nom de la variable, le traduira en adresse mémoire et ira rechercher l’information en mémoire à l’emplacement indiqué.

Passons maintenant à un aspect plus pratique et voyons la syntaxe à utiliser pour manipuler des variables.

02 ) Créer une variable .

La définition d’une variable se fait de manière très naturelle, comme en mathématique : identifiant=valeur (attention de ne surtout pas mettre d’espace entre la fin du nom de la variable et le signe égal !). La valeur pourra bien sûr être un nombre, une lecture ou chaîne de caractères (encadrée par des guillemets « … » ou des quotes « … ») ,ect.

Pour utiliser la valeur contenue dans une variable, il faudra la faire précéder du caractère $. Ainsi, si la variable a vaut 15, pour accéder à la valeur de a je devrais écrire $a.

reprenons l’exemple utilisé pour notre premier script (hello.sh), où le texte à afficher sera cette fois placé dans une variable :

#!/usr/bin/bash

msg=« Hello GNU/Linuxiens ! »
echo $msg

11

msg est la variable contenant la chaîne de caractères « Hello GNU/Linuxiens ! » et $msg représente le contenu de la zone mémoire référencée par le nom de la variable msg. Ainsi, lors de l’exécution, $msg sera remplacé par la valeur « Hello GNU/Linuxiens ! » et nous exécuterons donc echo « Hello GNU/Linuxiens ! ».

Il également possible d’exécuter des opérateurs sur les variables. Si les variables sont des entiers, on pourra utiliser les opérateurs arithmétiques classiques, plus % pour le reste de la division entière et ** pour la puissance. La syntaxe est alors un peu particulière et il y a deux manière de faire :

01 ► soit on encadre l’opération par $((…)), ce qui donne par exemple : a=$((7+8))
02 ► soit on utilise la commande let <> : let <<a=7+8>>

Dans le cas des chaînes de caractères, pour réaliser une concaténation (coller des chaînes bout à bout), il suffit de mettre les variables côte à côte. Par exemple si a=>>GNU/>> et b=>> Linuxiens>>, alors on peut écrire msg=$a$b et la variable msg contiendra la valeur « GNU/Linuxiens ».

Voici un tableau récapitulatif indiquant la valeur d’une variable après les opérations vues en exemple :

01 )
► COMMANDE => var=7+8
VALEUR DE LA VARIABLE => 7+8
(résultat de : echo $var)02 )
COMMANDE => let <<var=7+8>>
VALEUR DE LA VARIABLE => 1503 )
COMMANDE => var=$((7+8))
► VALEUR DE LA VARIABLE => 1504 )
COMMANDE => a=>>Hello GNU/>>
                                  var=$a>>Linuxiens>>
VALEUR DE LA VARIABLE => GNU/Linuxiens05 )
COMMANDE => a=>>Hello GNU/>>
                                  b=>>Linuxiens>>
                                  var=$a$b
VALEUR DE LA VARIABLE => Hello GNU/Linuxiens

03 ) Les différents types de variables.

3.1Les variables d’environnement :

Les variables d’environnement sont notées en majuscules. La partie 02 de la série d’articles sur la « ligne de commandes » explique déjà assez longuement à quoi servent ces variables. Sachez simplement que, d’un point de vue syntaxique, pour avoir accès à leur valeur, vous pourrez les utiliser comme des variables « normales » en préfixant leur nom par le caractère $.

3.2Variables spéciales :

Il existe un certain nombre de variables spéciales qui sont initialisées au lancement de chaque script. Voici un tableau les résumant :

VARIABLE => $0
DESCRIPTION => le nom du script (par exemple, si le script se nomme monScript.sh et qu’il est appelé depuis son répertoire de stockage, la valeur de $0 sera ./monScript.sh)► VARIABLE => $1, $2, …
DESCRIPTION => les arguments passés au script : $1 est le premier argument, ect.► VARIABLE => $*
DESCRIPTION => la liste de tous les arguments passés au script, séparés par un espace.► VARIABLE => $#
DESCRIPTION => le nombre d’arguments passés au script.► VARIABLE => $7
DESCRIPTION => le code de retour de la dernière commande exécutée. Toutes les commandes shell renvoient une valeur : 0 lorsque la commande s’est exécutée correctement et sinon, un code d’erreur compris entre 1 et 255. Par exemple, après un appel à ls , $? contiendra la valeur 0. Par contre, après un appel à ls /rep_inexistant , $7 contiendra la valeur 2 (on suppose que le répertoire /rep_inexistant n’existe pas, bien sûr).► VARIABLE => $!
DESCRIPTION => le numéro de processus de la dernière commande lancée en tâche de fond.► VARIABLE => $$
DESCRIPTION => le numéro de processus du script lui-même.

Grâce à ces variables, l’utilisateur pourra transmettre des données au script sans pour autant avoir à modifié le script. On peut donc définir des actions génériques, que l’on modifiera lors de l’appel en indiquant un ou plusieurs arguments.

Voici un exemple très simple permettant de voir le contenu de ces variables en fonction des arguments passés lors de l’appel du script.
Nous nommerons ce script variables.sh :

#!/bin/bash

echo « Le script s’appelle » $0
echo « Vous avez passé » $# « arguments. »
echo « La liste de ces arguments est : »
echo $*
echo « Le premier argument est : » $1
echo « Le deuxième argument est : » $2

12

Lors de l’exécution de ce script, si vous lui passez en paramètres quelques valeurs, vous obtiendrez l’affichage suivant :

~# bash variables.sh arg1 arg2 arg3
Le script ………
……………………………
………………………………………

12-1

Si, plutôt que de transmettre les données au script sous forme d’arguments, vous préférez demander à l’utilisateur de les saisir au clavier durant l’exécution de votre code, vous pourrez le faire grâce à la commande read .Cette commande permet de lire des données au clavier et de les stocker dans une variable dont le nom est spécifié à la suite de la commande : read nomVariable. La variable contenant la saisie utilisateur sera alors utilisée comme n’importe quelle variable en la préfixant par le caractère $ pour avoir accès à sa valeur.

Voici un exemple utilisant la commande read :

#!/usr/bin/bash

echo « Comment vous appelez-vous ? »
read nom
echo « Salut » $nom

13

À la lecture de la ligne 4, l’exécution du script sera suspendu jusqu’à ce que l’utilisateur ait saisi un texte et qu’il l’ait validé en appuyant sur la touche . Le texte sera alors stocké dans la variable nom et l’exécution du script reprendra en ligne 5 pour afficher le message.

Ce qui nous donne :

~# bash read.sh
Comment vous-appelez vous ?
………………
………………………………..

14

La commande read peut être utilisée pour réaliser une pause dans un programme en demandant à l’utilisateur d’appuyer sur la touche pour continuer. Ici, on ne souhaite pas récupérer la saisie dans une variable puisque cette dernière ne sera pas utilisée. Inutile dans ce cas de gaspiller de la mémoire, on ne précise pas de nom de variable :

echo « Appuyer sur pour continuer… »
read

04 EXÉCUTER DES COMMANDES SUIVANT DES CONDITIONS PRÉCISES.

Dans un script, il se peut que l’on veuille effectuer des actions différentes en fonction d’une valeur calculée ou transmise par l’utilisateur. Par exemple, à la question « Voulez-vous quitter le programme (O/N) ?« , il est bien évident que l’action à déclencher sera différente suivant que l’utilisateur réponde par l’affirmative ou la négative. Grâce aux structures conditionnelles nous allons pouvoir gérer ces cas.

01 ) La construction des structures conditionnelles.

Pour conditionner l’exécution de lignes de code, on utilise l’instruction if, qui se traduit par « si » et qui s’écrit de la manière suivante :

if condition; then
   …
fi

Les lignes encadrées par la ligne if et la ligne fi (if à l’envers) forment ce que l’on appelle « un bloc » : elles seront toutes exécutées (ou aucune) suivant que la condition du test soit vérifiée ou non. Le caractère point-virgule, qui suit la définition de la condition à vérifier, permet de séparer plusieurs commandes sur une même ligne.

L’instruction then (qui signifie « alors« ) étant une nouvelle instruction, il faut la séparer du début de ligne par un point-virgule. Sans ce caractère, il aurait fallu utiliser une notation moins compacte :

if condition
then
   …
fi

Cette structure permet donc d’exécuter des instructions au cas où la condition est vérifiée. Dans le cas où elle est invalidée, si vous souhaitez effectuer un autre traitement, il faudra utiliser l’instruction else dans une structure « si condition alors … sinon … » :

if condition; then

else
   …
fi

Enfin, on peut imbriquer les tests dans des structures de type « si condition_1 alors … sinon, si condition_2 alors sinon, si … ect. » :

if condition_1;   then
    …
elif condition_2;   then
    …
elif   …ect…
    …
fi

15

Nous avons vu la syntaxe permettant d’écrire des structures  contenant des embranchements s’activant en fonction de conditions …Il reste donc à voir comment écrire une condition pour pouvoir réellement utiliser ce mécanisme.

Une condition, encore appelée test, peut s’écrire de deux manières différentes :

► soit en l’encadrant par des crochets […]
► soit en utilisant la commande test …

Une fois la syntaxe choisie, en conjuguant cette écriture avec un opérateur de test, on obtient une condition. Avec des nombres par exemples, les opérateurs de test permettront d’écrire « Est-ce que a est plus petit que b ?« . L’opérateur « plus petit que » s’écrit -lt .

Voici un exemple de condition où nous employons les deux syntaxes décrites précédemment :

[ 2 -lt 3 ]
test 2 -lt 3

Ces deux lignes sont identiques et testent si 2 est inférieur ou égal à 3. Dans tout test, une condition vérifiée renverra 0 et sinon, un entier quelconque différent de 0. Si vous voulez vous en assurer, vous pouvez afficher le contenu de la variable spéciale $? après avoir exécuté un test :

~$ [2 -lt 3 ]
~$ echo $?
0

16

Si le nombre d’arguments est inférieur à 2 (ligne 3), alors on affiche un message d’erreur (ligne 4) et sinon, on affiche le nombre d’arguments (ligne 6).

02 ) Les opérateurs test.

Les opérateurs de test se répartissent en trois catégories : les opérateurs arithmétiques dont nous avons pu voir un exemple avec -lt, les opérateurs de test de fichiers, et les opérateurs logiques permettant de créer des conditions complexes.

02.1 – Les opérateurs arithmétiques :

L’opérateur arithmétique -lt, que nous avons déjà vu, signifie « low than » soit « inférieur à« ; Les autres opérateurs sont construits sur le même modèle : -gt pour plus grand que (greater than), -eq pour égal (equal), -ne pour différent de (not equal), -ge pour plus grand ou égal à (greater or equal), -le pour plus petit ou égal à (lower or equal).

Sachez que ces opérateurs sont des opérateurs arithmétiques et fonctionnent donc avec des nombres. Si vous voulez effectuer des tests sur des chaînes de caractères, vous devrez utiliser des opérateurs différents : == pour l’égalité et != pour la différence.

02.2 – Les opérateurs de test de fichiers :

Les opérateurs de test de fichiers permettent d’obtenir très facilement des informations sur les fichiers. Il s’agit la plupart du temps d’opérateurs unaires portant sur le nom d’un fichier. Voici quelques-uns de ces opérateurs :

-e : pour vérifier l’existence d’un fichier (exists).
-f : pour vérifier l’existence d’un fichier et qu’il s’agisse bien d’un fichier et pas d’un répertoire par exemple (file)
-d : pour vérifier l’existence d’un répertoire (directory).
-r : pour vérifier si un fichier est accessible en lecture (readable).
-w : pour vérifier si un fichier est accessible en écriture (writable)
-x : pour vérifier si un fichier a les droits d’exécution (executable).

02.3 – Les opérateurs logiques :

Les opérateurs logiques permettant de composer des conditions plus « complexes » à l’aide des opérateurs booléens « et« , « ou » et « non« .

L’opérateur « non » est un opérateur unaire : il n’accepte qu’un seul argument dont il va inverser la valeur retour . Si une conditions est vraie, alors elle sera fausse et inversement. Le symbole de cet opérateur est !.

Si vous voulez tester si 10 est supérieur ou égal en 5 en ne connaissant que l’opérateur -lt (inférieur à), il faudra prendre la négation de la condition : [ ! 10 -lt 5 ].

Les opérateurs « et » et « ou » sont des opérateurs binaires permettant de composer des conditions « si condition_1 est vraie et/ou si condition_2 est vraie, alors …« . On utilise && ou -a pour l’opérateur « et » et || ou -o pour l’opérateur « ou« . Ces opérateurs peuvent être combinés à l’infini.

Pour tester si une variable var est comprise entre 1 et 10, on utilisera le test :
[ $var -ge 1 ] && [ $var -le 10 ].

Enfin, une commande permet d’obtenir la liste complète des opérateurs arithmétiques, de test de fichiers et logiques disponibles pour la création de conditions :

~$ info coreutils ‘test invocation’

1717-1

03 ) La structure case .

Il n’existe pas que l’instruction if pour créer des structures conditionnelles : pour les structures à choix multiples, il existe la structure case permettant d’effectuer un branchement sur des lignes de codes en fonction de la valeur contenue dans une fonction.

On peut voir cette structure comme un grand aiguillage ferroviaire, dont le numéro de voie est donné par le contenu d’une variable. Au niveau syntaxique, la valeur de la variable pour chaque cas possible sera suivie d’une parenthèse fermante et le bloc d’instructions à exécuter pour ce cas se situera entre la parenthèse fermante et les caractères ;; (une instruction vide signifiant la fin du bloc).

Appliquons cette définition à un exemple : la variable choix peut valoir 1,2,3 ou 4 et l’action à effectuer sera simplement d’afficher le chiffre correspondant en toutes lettres pour les valeurs 1 à 3 et d’afficher le message « coucou » pour la valeur 4. Dans tous les autres cas, nous afficherons un message d’erreur.

Voici le code correspondant à cet exemple :

#!/bin/bash

echo « Donnez un chiffre entre 1 et 4 : »
read choix

case $choix in
1)   echo   « un »;;
2)  echo   « deux »;;
3)  echo    « trois »;;
4)  echo    « coucou »;;
*)  echo    « ERREUR ! »
esac

1818-1

Le dernier cas, en ligne 11, correspond au choix par défaut : si l’utilisateur saisit autre chose qu’un entier entre 1 et 4, c’est cette action qui sera effectuée. L’utilisation du caractère * pour indiquer tous les cas différentes de ceux traités (on dira « filtrés« ) auparavant, vient du fait qu’il s’agit en fait d’expressions régulières. En ligne 12, on referme le bloc case en inscrivant le nom de l’instruction à l’envers : esac .

04 EXÉCUTER PLUSIEURS FOIS UNE COMMANDE SANS AVOIR À LA RÉ-ÉCRIRE.

Une boucle permet de répéter une action , une commande ou un bloc de commandes un certain nombre de fois. Ces commandes pourront être exécutées à l’identique ou paramétrées à l’aide de variables qui évolueront à chaque passage dans la boucle. Si vous voulez afficher les 100 premiers résultats de la table de multiplication par 7, vous n’allez certainement pas écrire 100 lignes de code et calculer « à la main » les résultats ! D’où l’intérêt des boucles …

01 ) Les structures de base.

Le shell propose deux structures de boucles « simples » dont le fonctionnement général est identique : un bloc de commandes va être exécuté jusqu’à ce qu’une condition change d’état.

01.1 L’instruction « while » :

La première des structures de boucle est composée à l’aide de l’instruction while et signifie « tant que la condition est vérifiée, faire…« .

Dans le cas proposé en exemple, l’écriture des cents premiers résultats de la table de multiplication par 7, nous allons avoir besoin d’une variable i qui sera incrémentée et sera multipliée par 7 à chaque étape. La condition sera donc : « tant que i est inférieur ou égal à 100, faire…« . La traduction en script shell donne :

#!/bin/bash

i=1

while $i -le 100 ];  do
              echo  $i« *7= »$(($i*7))
              i=$(($i+1))
done

2020-1

En ligne 3, nous commençons par initialiser une variable i avec la valeur 1. Cette variable va nous permettre de compter de 1 à 100 pour effectuer nos calculs. Ce décompte va être contrôlé par la condition d’arrêt de notre boucle en ligne 5, qui peut être traduite par « tant que i est inférieur ou égal à 100, faire » . Vous reconnaîtrez dans l’écriture de la condition la syntaxe que nous utilisons avec les structures conditionnelles. Nous pouvons ensuite réaliser l’afficher en ligne 6 et surtout, ne pas oublier d’incrémenter la variable de boucle en ligne 7, de manière à pouvoir sortir de la boucle à un moment donné.

01.2L’instruction « until » :

La deuxième structure de boucle est la structure until, qui se rapproche énormément de la boucle while… à la différence prêt que la condition d’arrêt n’est pas interprétée de la même manière. En effet, until signifie « jusqu’à ce que… » et la boucle sera donc exécutée jusqu’à ce que la condition soit vérifiée (au contraire de la boucle while qui s’exécute tant que la condition est vérifiée).

Reprenons l’exemple utilisé précédemment avec le while : vous constaterez qu’une ligne sera modifiée. Mais attention : la condition a été inversée ! On passe ainsi de « tant que i < 100 » à « jusqu’à ce que i > 100« .

#!/bin/bash

i=1

until     [ $i -gt 100 ]; do
              echo  $i« *7= »$(($i*7))
              i=$(($i+1))
done

21
02 ) Parcourir une liste.

Le shell propose des instructions permettant de parcourir simplement une liste.

02.1 L’instruction « for » :

Cette structure s’éloigne un peu des deux types de boucles vus précédemment : ici, nous allons parcourir une liste d’éléments (chaînes de caractères, entiers ou mélange de plusieurs types). Une liste est spécifiée par une suite d’éléments séparés par un espace.

Voici un exemple de liste :

« chaîne » 1 2 « autre chaîne » 3 4 5

L’utilisation du caractère * permet d’obtenir un élément de type liste : les fichiers du répertoire courant. Il s’agit d’un joker qui peut être également combiné avec d’autres caractères *.py renverra par exemple la liste des fichiers Python du répertoire courant,  script* renverra  la liste des fichiers dont le nom commence par « script ». Pour parcourir les fichiers d’un répertoire, vous pourrez donc utiliser for en association avec le caractère *.

La construction de la boucle se fait à l’aide d’une variable qui va prendre consécutivement pour valeur les éléments de la liste. La syntaxe sera la suivante : for variable in liste; do que nous pourrions traduire par « pour la variable nommé variable prenant ses valeurs dans la liste, faire…« . N’oubliez pas que lors de l’utilisation de la variable, il faut préfixer son nom par la caractère $.

Voici par exemple comment afficher et compter les fichiers du répertoire courant à l’aide de cette structure :

#!/bin/bash

i=1

for file in *; do
          echo $i« . « $file
          i=$(($i+1))
done

2222-1

En ligne 5, le caractère * va être remplacé par la liste des fichiers. À chaque itération, la variable file va changer la valeur et contenir le nom d’un des fichiers du répertoire courant. Donc, à la première itération, $file désignera le premier fichier, puis à la deuxième itération, le deuxième fichier, et ainsi de suite.

02.2 L’instruction select pour une boucle un peu particulière :

L’instruction select est une sorte d’amélioration du for pour des cas particuliers. En effet, elle permet de proposer à l’utilisateur de saisir un choix dans une liste qui sera affichée à l’écran. Sans commande d’arrêt (que nous verrons par la suite), la demande saisie sera infinie.

Voici un exemple simple :

#!/bin/bash

select choix in « entrée 1 » « entrée 2 » ; do
         echo « Vous avez choisi » $choix
done

22

Lors de son exécution, ce script va réaliser l’affichage suivant :

22-1

Vous pourrez saisir votre choix après le point d’interrogation et la variable choix prendra pour valeur votre saisie (à condition que cette dernière fasse partie des choix possibles ; (1 & 2)).

Attention: vous devez taper le numéro correspondant à votre choix et la variable choix ne contiendra pas ce numéro mais le contenu correspondant à cet indice !

Comme dit précédemment, ce script boucle à l’infini et demandera toujours à l’utilisateur de saisir un choix. Pour arrêter la boucle, il faut utiliser break.Le menu ressemblera alors à:

#!/bin/bash

select choix in « entrée 1 » « entrée 2 » « q »; do
                  case $choix in
             « entrée 1 » | « entrée 2 ») echo « Vous avez choisi » $choix;;
            « q ») echo « Au revoir… »
                  break;;
             *) echo « Saisie non valide ! »
                    esac
done

2424-1

Ainsi, avec ce genre de structure, on assure que la boucle sera exécutée tant que l’utilisateur ne saisit pas un choix valide et que le menu sera ré-affiché jusqu’à ce que l’utilisateur sélectionne le choix 3 (test de la ligne 6 et sortie de la boucle select par le break de la ligne 7). Si vous souhaitez également interrompre la boucle dès qu’un choix valide a été sélectionné, vous pouvez également utiliser des break.

Créer une structure équivalente à l’aide des instructions for et while serait légèrement plus complexe :

i=1
for choix in « entrée 1 » « entrée 2 » « q » ; do
              echo $i« ) » $choix
             i=$(($i+1))
donewhile [ 1 ]; do
                   echo -n « #? « 
                   read choix
                   case $choix in
                   1 | 2) echo « Vous avez choisi l’entrée n. » $choix;;
                   3) echo « Au revoir… »
                            break;;
                   *) echo « Saisie non valide ! »
              esac
done

 

Il faut commencer par afficher les choix possibles (ligne 1 à 5), puis rentrer dans une boucle infinie en ligne 7 dont la condition d’arrêt est [ 1 ] (qui est toujours vrai) et enfin, demander à l’utilisateur de saisir un choix (notez l’usage de l’option -n de echo en ligne 8 pour désactiver le retour chariot) et traiter ce choix. Comme ici il n’y pas de correspondance entre le numéro saisi et la valeur du choix, nous récupérons dans la variable $choix que le numéro saisi. Dans ce cas particulier, il est donc bien plus pratique d’utiliser l’instruction select !

2525-1

CHOSES À RETENIR ET ASTUCES :

► Un éditeur de texte ne sauvegarde que le texte tapé au clavier. Un logiciel de traitement de texte tapé au clavier, ainsi que sa mise en forme (police, style, ect.).

► Dans les éditeurs de texte, la coloration syntaxique ne s’active en général qu’une fois le fichier enregistré avec la bonne extension (.sh pour les scipts shell).
Commencez donc par enregistré votre fichier avant de taper la moindre ligne de code !

► Les caractères #! sur la première ligne d’un fichier indiquent au système que ce fichier est un script qui doit être interprété par le programme indiqué à la suite sur cette même ligne, appelée « shebang »
À la lecture de la ligne #!/bin/bash, le système va exécuter la commande /bin/bash et lui fournir en entrée de lignes suivantes du fichier.

► Pensez à commenter abondamment vos lignes de code ! Elles vous semblent évidentes au moment où vous les écrivez, mais si vous devez relire votre programme plus tard, elles vous paraîtront nettement moins compréhensibles.

► Comme le shell est sensible à la case (différence majuscules/minuscules), il est d’usage de n’utiliser que des caractères minuscules pour nommer ses variables. Les noms en majuscules sont réservés aux variables d’environnement.

PASSER DES ARGUMENTS À UN SCRIPT :
Les variables spéciales $1, $2, … $n permettent de récupérer les arguments transmis à un script lors de son appel. La correspondance entre les noms de variables et les arguments se fait en fonction de la position de ces derniers :
~$ monScript.sh argument1 argument2 argument3 s0 s1 s2 s3

LES DANGERS DE LA COMMANDE READ :
En employant la commande read suivie de plusieurs noms de variables, vous pourrez récupérer plusieurs valeurs saisies par l’utilisateur, le caractère espace faisant office de délimiteur. Mais attention ! Si l’utilisateur donne plus de valeurs que ce qu’il n’y de variables dans la commande read, votre dernière contiendra tous les caractères restants. Voici un petit exemple illustrant le principe :
~$ echo « Saisir a et b: »; read a b; echo « a = » $a « et b = » $b GNU/Linuxiens a = GNU/ et b = Linuxiens
~$ echo « Saisir a et b: »; read a b; echo « a « et b= » $b GNU/Linuxiens test de variables a = GNU/Linuxiens et b = test de variables

► ATTENTION AUX ESPACES !
Lors de l’écriture de conditions en la syntaxe […], faites très attention à bien laisser un caractère espace après le crochet ouvrant et avant le crochet fermant :
~$ [2 -lt 3]
[2 : commande introuvable
~$ [ 2 -lt 3]
bash: [:  » ]  » manquant
~$ [ 2 -lt 3 ]
La dernière ligne ne renvoie pas d’erreur et fonctionne donc correctement.

► Chaque passage dans une boucle s’appelle une itération et si la condition d’arrêt porte sur une variable, cette dernière se nomme variable de boucle.
Il faut faire très attention à ce que la condition d’arrêt de la boucle puisse changer d’état à un moment donné, sinon votre script rentrera dans une boucle infinie et vous ne pourrez l’arrêter qu’à l’aide de [Ctrl]+[C]. Ce genre de condition dépend en général d’une variable de boucle qu’il faudra prendre soin de faire évoluer au cours des itérations (soit en l’incrémentant, soit en la décrémentant.)

► À chaque fois que vous utilisez le caractère * dans une commande shell, celui-ci est remplacé par la liste des fichiers du répertoire courant. Par exemple, si votre répertoire contient trois fichiers : monFichier.txt ; monTest.sh et monTest.py, le caractère * dans une commande sera remplacé par la liste de ces fichiers :
~$ echo mo*
monFichier.txt monTest.sh monTest.py

Voilà, nous en avons terminé pour cette quatrième parties.

La cinquième parties sera accès sur la recherche de fichier, la gestion des utilisateurs, la gravure et l’encode de CD/DVD et il y aura une partie sur le réseau (interfaces, SSH, bureau à distance-graphique, partage de fichiers et la sauvegarde de données.)

À très vite … Merci.

logo_gnu_linux_pratique

Votre commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l’aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google

Vous commentez à l’aide de votre compte Google. Déconnexion /  Changer )

Image Twitter

Vous commentez à l’aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l’aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s