Programmation Shell (Scripts)
Objectifs spécifiques
- Manipuler les variables
- Manipuler les paramètres de position
- Découvrir les commandes internes
- Utiliser les structures conditionnelles
- Utiliser les structures itératives
I. Introduction
Le shell est l’interface Homme/Machine d’UNIX. Il en existe plusieurs qui diffèrent par la
syntaxe mais aussi par les services offerts.
Le shell a un double rôle, celui d’interpréteur de commandes mais aussi celui d’un langage
de programmation et à ce titre, il gère des variables et des fonctions et dispose de structures de
contrôle (boucles, conditionnelles ….). Ces fonctionnalités servent essentiellement pour
l’écriture de procédures (shells scripts) qui permettent à chacun de paramétrer une session et
développer ses propres outils.
Dans le fichier /etc/passwd, il y a certaines informations concernant les utilisateurs et
notamment le shell qu'ils utilisent, par exemple :
nico:x:1000:1000:nico:/home/nico:/bin/bash
Pour savoir tous les shells qui sont disponibles sur votre machine, vous pouvez taper :
ls /bin | grep sh
II. Structure d’un script
Un script bash est un simple fichier texte exécutable (droit x) commençant le nom de
l'interpréteur de commandes
#!/bin/bash
Voici un exemple de script :
#!/bin/bash
…
echo “voici un script bash“
…
De même que tout autre programme, Shell peut également prendre des arguments dans un
fichier.
Commentaires: Les lignes de commentaires débutent par #.
1
Exécution du script : Pour exécuter le script, o n d o i t d'abord vérifier qu’on a le droit
d'exécuter ce fichier et puis taper:
./monfichier
III. Variables
1. Noms des variables
Les noms des variables peuvent être composés:
- soit d'une suite de lettres, de chiffres et du caractère _.
- soit d'un chiffre
- soit de l'un quelconque des caractères * @ # ? - $ !.
Le premier cas correspond aux variables créées par l'utilisateur, le deuxième cas correspond
aux paramètres des fichiers de commandes, le troisième cas correspond à un ensemble de
variables gérées par le Shell.
2. Variables prédéfinies (variables spéciales du Shell)
Il y a des variables prédéfinies par le Shell, ces variables sont appelés variables
d’environnement. Ci-dessous, les principales variables utilisées par le Shell.
HOME : contient le chemin absolu du répertoire de connexion de l’utilisateur
LOGNAME : contient le nom de connexion de l’utilisateur
PATH : contient la liste des répertoires contenant des exécutables séparés par ‘ :’. Ces
répertoires seront parcourus par ordre à la recherche d’une commande externe. Si la
commande ne se trouve pas dans la liste des répertoires indiquée alors la commande ne sera
pas reconnue.
SHELL : contient le chemin d’accès absolu des fichiers programmes du shell
IFS: caractère de séparation des arguments
Note :
La commande env permet d’afficher l’ensemble des variables d’environnement pour le
shell actif
Exemple :
$ echo “le répertoire de connexion est : $HOME“
Le répertoire de connexion est : /home/isetch
3. Variables définies par l’utilisateur
a. Déclaration et types des variables
Il n'est pas nécessaire de déclarer une variable avant de l'utiliser. Les objets possédés par les
variables sont d'un seul type : la chaîne de caractères.
b. Affectation d'une valeur à une variable
2
Pour affecter une valeur à une variable, il suffit de taper le nom de variable, suivi du signe
égal, suivi de la valeur que l’on désire affecter à la variable.
La syntaxe d'une affectation est la suivante :
nom-de-variable = chaîne-de-caractères
$V1=aaa
$V2=A2
$REP=/usr/include
Attention à ne pas laisser des espaces autour du signe =.
Pour référencer la valeur d’une variable, on utilise la notation consistant à écrire le
signe $ suivi du nom de la variable.
Pour supprimer une variable déjà déclarée, on utilise la commande unset dont la syntaxe
est la suivante :
unset nom_variable
Exemple 2 :
$ a=salle
$ b=informatique
$ echo “c’est la $a $b “
c’est la salle informatique
$ unset b
$ echo “c’est la $a $b “
c’est la salle
c. Affectation d'une chaîne vide
On peut affecter une chaîne vide à une variable de 3 manières différentes:
V1=
V2=' '
V3=""
d. Affectation et interprétation des blancs
Si la chaîne-de-caractères à affecter à la variable comporte des blancs, il faut l’entourer à l'aide
des quotes.
$ MESSAGE='Bonjour a tous'
e. Affectation et substitutions
Il est possible de stocker le résultat d'une commande dans une variable. Le résultat c’est la
chaîne affichée par la commande, et non son code de retour. Bash utilise plusieurs notations
pour cela : les back quotes (anti-apostrophes) ou les parenthèses :
DATE=`date`
3
PERSONNE=$USER
La variable DATE va mémoriser la date courante, la variable PERSONNE va recevoir la
valeur de la variable USER.
$ JeSuis=$(logname)
$ echo $JeSuis
isetch
La commande peut être compliquée, par exemple avec un tube :
$ Fichiers=$(ls /usr/include/*.h | grep std)
$ echo $Fichiers
/usr/include/stdint.h /usr/include/stdio_ext.h /usr/include/stdio.h
/usr/include/stdlib.h /usr/include/unistd.h
4. Paramètres de positions
A l’intérieur du script, les arguments peuvent être référés par des paramètres spéciaux
(connus sous le nom de paramètres positionnels).
Le métacaractère “$” est utilisé pour référer aux arguments d’une commande :
$? : valeur de retour de la dernière commande exécutée
$$ : numéro du processus (PID) du shell actif
$! : numéro du processus (PID) du dernier processus lancé en arrière plan
$0 : nom de procédure de commande
$1….$9 : valeur de nième paramètre
$# : nombre de paramètre transmis à l’appel
$* : liste de tous les paramètres $1……$9
$@ : liste des paramètres sous la forme “$1“, “$2“,…., “$9“
$# donne le nombre d’arguments donnés à l’appel et $* est utilisé si l’on veut substituer tous
les arguments sauf le nom de commande ($0).
Le programme suivant illustre l'utilisation de ces variables :
#!/bin/bash
echo 'programme :' $0
echo 'argument 1 :' $1
echo 'argument 2 :' $2
echo 'argument 3 :' $3
echo 'argument 4 :' $4
echo "nombre d'arguments :" $#
echo "tous:" $*
4
Exemple d'utilisation, si le script s'appelle "myargs " :
$ ./myargs un deux trois
programme : ./myargs
argument 1 : un
argument 2 : deux
argument 3 : trois
argument 4 :
nombre d'arguments : 3
tous: un deux trois
5. Exportation de variables
Une variable est locale à un processus et elle n’est pas automatiquement connue dans les
processus crées pour exécuter des commandes ou des scripts. Certaines variables prédéfinis
sont automatiquement exportées par le shell (comme HOME). Pour exporter une variable on
utilise la commande export avec en argument les variables concernées. Sans paramètre, export
affiche la liste des variables exportées.
$ cat exemple
echo "Dans exemple, v=$v "
$ v=oui
$ exemple
Dans exemple, v=
$ export v
$ exemple
Dans exemple, v=oui
6. Code de retour d'un programme ou d’une commande
Quand le Shell lance l'exécution d'un programme en avant plan, il attend la fin de
l'exécution. Le Shell affecte le code de retour du programme à la variable ? dénoté par $?,
que l'on peut manipuler comme n'importe quelle variable.
On suppose que l’utilisateur toto n’est pas défini dans le système :
$ grep toto /etc/passwd
$ echo $?
1
$ grep isetch /etc/passwd
isetch:x:40:226:utilisateur isetch:/users/isetch:/bin/bash
$ echo $?
0
Si le code retour de la commande est nul, ça signifie que la commande ou le programme a été
bien exécuté sans erreur. Si le code retour est non nul, ceci signifie que la commande a
rencontré des erreurs lors de son exécution.
5
IV. Commandes internes
1. Commande read
read liste-de-variables
La commande read lit une ligne sur l'entrée standard, la découpe en mots séparés par des
espaces et affecte chaque mot aux variables de la liste-de-variables. Si la ligne lue comporte
plus de mots que la liste-de-variables comporte, il affecte à la dernière variable l'ensemble
des mots restant à affecter.
Exemple d'utilisation:
read c1 c2 c3
echo c1 = $c1 c2 = $c2 c3 = $c3
2. Commande test
Elle permet d’effectuer des tests de comparaison, en retournant un code de sortie égal à zéro
lorsque la comparaison est vraie, égal à 1 si faux et une autre valeur sinon.
Ces c o m p a r a i s o n s p e u v e n t ensuite être testées dans une structure if, while ou
until.
La syntaxe de la commande :
test prédicat
ou
[ prédicat ]
Remarque : Il ne faut pas oublier les espaces de part et d’autres des crochets.
a. Opérateurs de comparaison:
Opérateur Description Exemple
Opérateurs sur des fichiers
-e fichier vrai si fichier existe [ -e /etc/shadow ]
-d fichier vrai si fichier est un répertoire [ -d /tmp/trash ]
-f fichier vrai si fichier est un fichier ordinaire [ -f /tmp/glop ]
-L fichier vrai si fichier est un lien symbolique [ -L /home ]
-r fichier vrai si fichier est lisible (r) [ -r /boot/vmlinuz ]
-w fichier vrai si fichier est modifiable (w) [ -w /var/log ]
-x fichier vrai si fichier est exécutable (x) [ -x /sbin/halt ]
fichier1 -nt fichier2 vrai si fichier1 plus récent que fichier2 [ /tmp/foo -nt /tmp/bar ]
fichier1 -ot fichier2 vrai si fichier1 plus ancien que fichier2 [ /tmp/foo -ot /tmp/bar ]
Opérateurs sur les chaînes
-z chaine vrai si la chaine est vide [ -z "$VAR" ]
-n chaine vrai si la chaine est non vide [ -n "$VAR" ]
chaine1 = chaine2 vrai si les deux chaînes sont égales [ "$VAR" = "totoro" ]
vrai si les deux chaînes sont
chaine1 != chaine2 [ "$VAR" != "tonari" ]
différentes
Opérateurs de comparaison numérique
6
num1 -eq num2 égalité [ $nombre -eq 27 ]
num1 -ne num2 inégalité [ $nombre -ne 27 ]
num1 -lt num2 inférieur ( < ) [ $nombre -lt 27 ]
num1 -le num2 inférieur ou égal ( < =) [ $nombre -le 27 ]
num1 -gt num2 supérieur ( > ) [ $nombre -gt 27 ]
num1 -ge num2 supérieur ou égal ( > =) [ $nombre -ge 27 ]
b. Combinaison de prédicats
! (Négation logique)
-a (ET logique)
-o (OU logique)
Pour des comparaisons complexes, on peut utiliser des parenthèses précédées de caractère
\. Par exemple l’expression : !comparaison1 –a comparaison2 peut être
écrite : !\(comparaison1 –o comparaison2\)
Pour tester si la variable chaîne a comme valeur la chaîne vide, on ne peut pas écrire :
test $chaîne = ‘ ‘, car si cette chaîne est vraiment vide et après évaluation des méta
caractères, cette commande sera évalué sous la forme : test = ‘ ‘ qui est incorrecte. D’où
l’introduction de la syntaxe suivante pour tester si chaîne est une chaîne vide : test $chaîne
3. Commande expr
Syntaxe:
expr arguments...
Cette commande évalue les arguments comme une expression. Le résultat est envoyé sur la
sortie standard. arguments est une expression comprenant des opérateurs.
• exp1 + exp2: addition.
• exp1 - exp2: soustraction.
• exp1 \* exp2 : multiplication.
• exp1 / exp2: division.
• exp1 \% exp2: modulo.
• chaîne: renvoie chaîne sur la sortie standard si la chaîne est non vide, 0 sinon.
• exp1 \ | exp2: retourne exp1 si elle est non nulle et non vide, sinon retourne exp2 si exp2
est non nulle et non vide, sinon retourne 0.
• exp1 \ & exp2: retourne exp1 si aucune des expressions n’est vide ou nulle, 0 sinon.
• exp1 op_comp exp2: où op_comp est un opérateur de comparaison (<, <=, =, !=, >=,>);
retourne 0 si vrai, 1 sinon.
7
exemple :l’instruction var = ‘expr $var + 1‘ affecte à la variable var la valeur de a incrémentée de 1.
V. Structures conditionnelles
1. Structure if
Syntaxe
if condition1
then
liste_commande1
elif condition2
then
liste_commande2
else
liste_commande3
fi
En shell, la valeur zéro est associée à la valeur booléenne vraie et toute autre valeur correspond
à la valeur faux. Les parties elif et else sont optionnelles.
Exemple:
if test −d $1
then echo "$1 est un répertoire"
elif test −f $1
then echo "$1 est un fichier"
elif test −L $1
then echo "$1 est un lien symbolique"
else echo "$1 autre ..."
fi
Remarque :La condition à tester par l’instruction if peut être une combinaison de plusieurs
conditions.
Par exemple :
if cond1 && cond2
then
liste_commande1 il faut que cond1 et cond2 soient vrais pour que
8
else liste_commande1 soit exécutée
liste_commande2
fi
if cond1 || cond2
then
liste_commande1 il faut que cond1 ou cond2 soient vrais pour que
else liste_commande2 soit exécutée
liste_commande2
fi
2. Structure case
Syntaxe
case mot in
liste-de-modèles ) liste-de-commandes ;;
liste-de-modèles ) liste-de-commandes ;;
esac
Dans les listes-de-modèles les modèles sont sépares par le caractère |.
Exemples
case $langue in
francais) echo "Bonjour" ;;
anglais ) echo "Hello" ;;
italien ) echo "Bongiorno" ;;
esac
case $param in
0|1|2|3|4|5|6|7|8|9 ) echo "$param est un chiffre";;
[0-9]* ) echo "$param est un nombre";;
[a-zA-Z]* ) echo "$param est un nom";;
* ) echo "$param de type non défini";;
esac
case $1 in
one)X=un;;
two)X=deux;;
three) X=trois;;
*) X=$1;;
esac
echo "voulez vous continuer :"
read reponse
case "$reponse" in
[nN] | no | NO) echo "Quitter";;
[yY] | yes | YES) echo "Continuer";;
9
*) echo "Réponse non valide";;
esac
VI. Structures itératives
1. Boucle for
a. Syntaxe
for nom in liste_mots
do
done
b. Exemple
Cette séquence Shell recopie tous les fichiers *.c du répertoire courant dans le répertoire rep.
for i in *.c
do
cp $i rep
done
Cet exemple permet d’afficher le type de chaque fichier dans l’ensemble
for fichier in essai1 essai2 essai3
do
file $fichier
done
La liste de mots à parcourir peut être aussi le résultat d’une commande. Cet exemple permet
de parcourir le fichier /etc/passwd ligne par ligne et affiche le nom d’utilisateur correspond
à chaque ligne.
for ligne in $(cat /etc/passwd)
do
USER=$(echo $ligne|cut –f1 –d “:”)
echo $USER
done
#changer les droits d’accès à rwxr-xr-x pour tous les #fichiers du
répertoire courant commençant par #l’extension ‘.c’
for fichier in ‘ls *.c’
do
chmod 755 $fichier
done
10
2. Boucle while
a. La syntaxe
La syntaxe est la suivante:
while commande
do
liste-de-commandes
done
b. Exemples
L'exemple ci-dessous réalise une boucle de 10 itérations et incrémente la variable i à chaque
instruction.
i=1
while (test $i -le 10)
do
i=`expr $i + 1`
done
Tant que l’utilisateur passé en argument est dans la liste de la commande who (donc parmi
les utilisateurs connectés), on boucle après avoir attendu 60 secondes. S’il n’est plus
connecté, la commande du while va retourner un code retour non nul (Faux), on signale
qu’il n’est plus connecté.
while who | grep "$1"
do
sleep 60
echo "\n$1 n’est plus connecté"
done
3. Boucle until
c. La syntaxe
La syntaxe est la suivante:
until commande
do
liste-de-commandes
done
d. Exemples
until who | grep "$1"
do
sleep 180
done
echo "\n$1 est arrivé"
Jusqu’à ce que l’utilisateur passé en argument se trouve dans la liste des utilisateurs (who |
grep $1), on fait une pause (sleep 180). Lorsque l’on sort de la boucle (alors l’utilisateur est
connecté), on affiche le message "utilisateur est arrivé".
11
4. Débranchements (break et continue)
Il est possible de sortir prématurément d’une boucle sans effectuer toutes les itérations
prévues, par le mot clé break. Cela permet de pouvoir sortir d’une boucle infinie, ou que la
sortie soit déclenchée par un événement autre que le test de boucle.
Le mot continue permet au contraire de faire une itération supplémentaire.
Exemple:
Ce script boucle en demandant un nom de fichier jusqu’à ce que la réponse désigne un
fichier existant.
#!/bin/bash
while
do
echo "nom de fichier: \n"
read fic
if test −f "$fic"
then
else
fi
done
# parcourir l’ensemble des fichiers du
#répertoire courant, #s’il n’est pas de type
#répertoire, alors créer un #portant ce nom
for f
do
if test –d $f then
continue
else
mkdir $f
fi
done
12