Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. Unix
  3. Les bases de la programmation shell
Extrait - Unix Les bases indispensables (avec exercices pratiques et corrigés) (3ième édition)
Extraits du livre
Unix Les bases indispensables (avec exercices pratiques et corrigés) (3ième édition) Revenir à la page d'achat du livre

Les bases de la programmation shell

Procédures et paramètres

Comme nous l’avons déjà mentionné, le shell est à la fois un interpréteur de commandes et un langage de programmation destiné à l’écriture de procédures utilitaires. En complément des informations présentées dans le chapitre Utilisation du shell, nous allons présenter maintenant les bases de la programmation shell. Sans prétendre traiter le sujet dans son intégralité, nous souhaitons disposer de compétences de premier niveau qui nous permettront de lire et de maintenir des scripts existants ainsi que d’écrire des procédures simples d’exploitation.

Nous choisissons de présenter des syntaxes communes aux deux interpréteurs ksh et bash. Par expérience, ce tronc commun de syntaxe est souvent suffisant pour l’écriture de la majorité des procédures d’exploitation. Tous les exemples présentés fonctionnent donc à l’identique dans le contexte des deux interpréteurs.

1. Procédures

Des séquences de commandes et d’instructions shell peuvent être regroupées dans un fichier qui devient ainsi, à son tour, une nouvelle commande du système. On parle de procédure ou de script. Nous utiliserons indifféremment l’un ou l’autre des deux termes dans la suite de ce chapitre.

La procédure est interprétée par un shell fils du shell de connexion (mécanisme du fork, chapitre Processus et mécanismes) et elle hérite donc des variables...

Instructions de contrôle

Nous présentons maintenant les principales instructions de contrôle disponibles. Dans les résumés de syntaxe, nous faisons apparaître en gras les mots-clés du langage.

1. Tests

a. Tests simples

Pour effectuer des tests simples, plusieurs syntaxes sont possibles :

if commande 
then 
    liste_de_commandes 
fi 

ou bien :

if commande ; then 
    liste_de_commandes 
fi 

ou bien :

if commande 
then 
   liste_de_commandes 
else 
   liste_de_commandes 
fi 

Dans les tests en shell, contrairement aux langages de programmation classiques, il est à noter que le if n’est pas suivi d’une expression booléenne mais bien d’une commande.

On considère qu’une commande est vraie lorsque son code retour est égal à zéro. 

Il est possible de placer plusieurs commandes (notamment un pipeline) après le if. Dans ce cas, le test prend en compte le code retour de la dernière de ces commandes.

Exemple


if who | grep toto > /dev/null 
then 
   echo "toto est connecte" 
else 
   echo "toto n'est pas connecte" 
fi
 

La redirection vers /dev/null permet d’éliminer la sortie de la commande grep en cas de succès. Nous ne sommes intéressés que par son code retour.

Il conviendrait aussi de fournir une expression régulière à la commande grep pour que le test soit vraiment correct.

b. Tests séquentiels

Il est possible d’effectuer des tests séquentiels. On exécutera la liste de commandes associée au premier test vrai pour quitter ensuite l’instruction. Si aucun test n’est vrai, les commandes associées à une éventuelle clause else seront exécutées.

Deux syntaxes sont disponibles :

if commande 
then  
   liste_de_commandes 
else if commande 
then 
   liste_de_commandes 
else if commande 
then 
  liste_de_commandes 
.......... 
.......... 
else 
  liste_de_commandes 
fi 
fi 
fi 

ou bien :

if commande 
then  
   liste_de_commandes 
elif commande 
then 
   liste_de_commandes 
elif commande 
then 
   liste_de_commandes 
.......... 
.......... 
else 
   liste_de_commandes 
fi 

L’utilisation de la syntaxe...

Fonctionnalités complémentaires

1. Tableaux

Le shell permet la manipulation de tableaux monodimensionnels. Les syntaxes disponibles sont les suivantes :

Affectation globale

set -A tab valeur1 valeur2 valeur3	 # Syntaxe ksh 
tab=(valeur1 valeur2 valeur3)        # Syntaxe bash
 

Désignation des éléments (les indices démarrent à zéro)


echo $tab        # le premier élément 
valeur1 
echo ${tab[2]}   # le troisième élément 
valeur3 
echo ${tab[*]}   # tous les éléments 
valeur1 valeur2 valeur3 
 

Affectation d’un élément

tab[0] =toto 
echo ${tab[*]} 
toto valeur2 valeur3
 

Nombre d’éléments


echo ${#tab[*]} 
3
 

2. La variable IFS

La variable système IFS précise le séparateur de champs lors des lectures (read) et des résultats de substitutions de commande ou de paramètres. Sa valeur par défaut est « espace, tabulation et interligne ».

Elle peut être modifiée ponctuellement pour traiter, par exemple, des lignes avec un séparateur différent.

Exemples


$ echo $PATH 
/home/michel/bin:/usr/local/bin:/usr/bin:/bin:/usr/games 
$ IFS=: 
$ for i in $PATH 
> do 
>    echo $i 
> done 
/home/michel/bin 
/usr/local/bin 
/usr/bin 
/bin 
/usr/games 
$ read var1 var2 
bonjour:salut 
$ echo $var1 
bonjour 
$ echo $var2 
salut 
$
 

Dans ces exemples, après modification de la variable IFS, une boucle for nous permet d’abord de traiter le contenu de la variable PATH. Ensuite, une lecture au clavier de deux variables nous impose d’utiliser le nouveau séparateur en lecture.

3. La commande interne shift

La commande interne shift permet de modifier la liste des paramètres en décalant ceux-ci vers la gauche.

$1 disparaît, $2 devient $1, $3 devient $2 etc. Bien entendu, le nombre de paramètres $# est décrémenté et la variable $* est mise à jour.

Concrètement, cette commande est utile dans la programmation des procédures à options (voir la commande getopts dans ce même chapitre). Elle permet en effet de se positionner au début de la liste des véritables arguments, après...

Quelques exercices

Les scripts que l’on se propose d’écrire ici peuvent indifféremment être écrits en ksh ou en bash.

Énoncés

1. Tests séquentiels


#  ex1 : Exemple de tests séquentiels 
#  On attend un argument exactement 
#  Si c'est un répertoire accessible, on fait la liste des fichiers. 
#  Sinon, s'il s'agit d'un "fichier texte", on affiche sa taille en octets 
#  Sinon, on affiche un message d'erreur
 

2. Boucle for


#  ex2 : Exemple de boucle for 
#  Liste des commandes du répertoire donné en argument. 
#  Si aucun argument, on traite le répertoire courant.
 

3. Boucle while


#  ex3 : Exemple de boucle while et de lecture clavier 
#  Récupérer l'heure système sous la forme hh:mm. 
#  Lire au clavier une heure postérieure (au même format). 
#  Si la saisie est vide, quitter le programme. 
#  Attendre cette heure via une boucle qui recalcule l'heure système 
#  toutes les 5 secondes.
 

4. Aiguillage


#  ex4 : Exemple d'aiguillage  
#  Proposer un menu 
 
cat <<FIN 
             1. QUELLE HEURE EST-IL ? 
             2. CHANGEMENT DE REPERTOIRE COURANT 
             == Les choix suivants concernent le répertoire courant == 
             3. LISTE DES COMMANDES 
             4. SAUVEGARDE DES FICHIERS ORDINAIRES (ARCHIVE TAR ZIPPEE) 
             5. LISTE D'UNE ARCHIVE 
             6. RESTAURATION INTERACTIVE D'UN FICHIER 
             0. SORTIE 
FIN 
 
# Il faudra indiquer dans cette variable l'emplacement des fichiers
# à inclure. 
rep_include=$HOME/bin 
 
# Il faudra inclure des définitions de variables et de fonctions. 
. ${rep_include}/mes_variables 2> /dev/null 
. ${rep_include}/mes_fonctions 2> /dev/null
 

5. Gestion des signaux


#  ex5 : Exemple de traitement des interruptions 
#  Faire grossir un fichier temporaire toutes les 5 secondes ...