Вы находитесь на странице: 1из 143

Introduction

la programmation en Bash
Version 0.2

Eric Sanchis

IUT, 50 avenue de Bordeaux, 12000 Rodez


Tl : 05.65.77.10.80 Fax : 05.65.77.10.81 Internet : www.iut-rodez.fr
Interprteur de commandes par dfaut des systmes GNU/Linux, bash est devenu pour les
administrateurs systme, un outil incontournable. Ce document prsente les principales
constructions syntaxiques de bash utilises dans lcriture des programmes shell (scripts
shell). Lobjectif premier a t de laisser de ct les redondances syntaxiques de ce langage de
programmation et la subtilit des mcanismes de linterprteur afin dinsister sur quelques
concepts synthtiques tels que la substitution, la redirection ou le filtrage.

Cette deuxime version a t revue et augmente. Document destin principalement aux


tudiants de premier et deuxime cycle en informatique, le style adopt devrait toutefois
permettre au lecteur ayant une premire exprience de la ligne de commande de
sapproprier les diffrentes notions prsentes. Ce dernier pourra ensuite aborder des ouvrages
plus extensifs ou plus spcialiss.

Cette publication tant loin dtre parfaite1, jencourage le lecteur me faire parvenir ses
remarques ou suggestions, ainsi qu me signaler toute inexactitude (eric.sanchis@iut-
rodez.fr).

Pour en savoir plus :

[1] Mendel Cooper, Advanced Bash Scripting Guide (http://tldp.org/LDP/abs/html).


Une traduction en franais est disponible (http://abs.traduc.org).

[2] Cameron Newham, Bill Rosenblatt, Le shell bash, 3me dition, Ed. OReilly, Paris,
2006.

[3] Carl Albing, JP Vossen, Cameron Newham, Bash : le livre des recettes, Ed. OReilly,
Paris, 2007.

[4] Arnold Robbins, Nelson H. F. Beebe, Introduction aux scripts shell, Ed. OReilly,
Paris, 2005.

Plate-forme logicielle utilise :


Interprteur bash 4.2, systme PC/Ubuntu 12.04

Licence :
GNU Free Documentation License

1
Les exemples figurant dans ce document ont pour but dillustrer les notions traites. Il nest donn
aucune garantie quant leur fonctionnement ou leurs effets.

1
Table des matires

Chapitre 1 : Introduction bash 6

1. Les shells 6
1.1 Un environnement de travail 6
1.2 Un langage de programmation 7
1.3 Atouts et inconvnients des shells 8
1.4 Shell utilis 8
2. Syntaxe dune commande 9
3. Commandes internes et externes 10
3.1 Commandes internes 10
3.2 Commandes externes 11
4. Modes dexcution dune commande 11
4.1 Excution squentielle 12
4.2 Excution en arrire-plan 12
5. Commentaires 13
6. Fichiers shell 13

Chapitre 2 : Substitution de paramtres 17

1. Variables 17
2. Paramtres de position et paramtres spciaux 23
2.1 Paramtres de position 23
2.2 Paramtres spciaux 25
2.3 Commande interne shift 25
2.4 Paramtres de position et fichiers shell 26
2.5 Paramtres spciaux * et @ 27
3. Suppression des ambiguts 28
4. Paramtres non dfinis 28
5. Suppression de variables 30
6. Indirection 30

Chapitre 3 : Substitution de commandes 33

1. Prsentation 33
2. Substitutions de commandes et paramtres rgionaux 35

Chapitre 4 : Caractres et expressions gnriques 38

1. Caractres gnriques 39
1.1 Le caractre * 39
1.2 Le caractre ? 40
1.3 Les caractres [] 41

2
2. Expressions gnriques 42
3. Options relatives aux caractres et expressions gnriques 44

Chapitre 5 : Redirections lmentaires 46

1. Descripteurs de fichiers 46
2. Redirections lmentaires 46
2.1 Redirection de la sortie standard 46
2.2 Redirection de la sortie standard pour les messages derreur 48
2.3 Redirection de lentre standard 50
2.4 Redirection spare des entres / sorties standard 51
2.5 Texte joint 51
2.6 Chane jointe 52
2.7 Fermeture des entres / sorties standard 53
3. Tubes 53
3.1 Pipelines 53
3.2 Tubes et chanes jointes 54
4. Substitution de processus 55

Chapitre 6 : Groupement de commandes 57

Chapitre 7 : Code de retour 60

1. Paramtre spcial ? 60
2. Code de retour d'un programme shell 63
3. Commande interne exit 63
4. Code de retour d'une suite de commandes 64
5. Code de retour dune commande lance en arrire-plan 65
6. Rsultats et code de retour 65
7. Oprateurs && et || sur les codes de retour 66

Chapitre 8 : Structures de contrle case et while 69

1. Choix multiple case 69


2. Itration while 71

Chapitre 9 : Chanes de caractres 77

1. Protection de caractres 77
1.1 Mcanismes 77
1.2 Exemples dutilisation 78
2. Longueur d'une chane de caractres 81
3. Modificateurs de chanes 82
4. Extraction de sous-chanes 84

3
5. Remplacement de sous-chanes 85
6. Transformation en majuscules/minuscules 86
7. Formatage de chanes 87
8. Gnration de chanes de caractres 90

Chapitre 10 : Structures de contrle for et if 91

1. Itration for 91
2. Choix if 93
2.1 Fonctionnement 93
2.2 Commande compose [[ 94

Chapitre 11 : Entiers et expressions arithmtiques 101

1. Variables de type entier 101


2. Reprsentation dune valeur de type entier 101
3. Intervalles dentiers 103
4. Commande interne (( 104
5. Valeur d'une expression arithmtique 106
6. Oprateurs 107
7. Structure for pour les expressions arithmtiques 113
8. Exemple : les tours de Hanoi 113

Chapitre 12 : Tableaux 115

1. Tableaux classiques 115


1.1 Dfinition et initialisation 115
1.2 Oprations sur un lment de tableau classique 116
1.3 Oprations sur un tableau classique 118
2. Tableaux associatifs 121
2.1 Dfinition et initialisation 121
2.2 Oprations sur un lment de tableau associatif 122
2.3 Oprations sur un tableau associatif 123

Chapitre 13 : Alias 125

1. Cration dun alias 125


2. Suppression dun alias 127
3. Utilisation des alias 128

Chapitre 14 : Fonctions shell 129

1. Dfinition dune fonction 129


2. Suppression dune fonction 132

4
3. Trace des appels aux fonctions 132
4. Arguments dune fonction 133
5. Variables locales une fonction 135
6. Exporter une fonction 137
7. Commande interne return 139
8. Substitution de fonction 140
9. Fonctions rcursives 141
10. Appels de fonctions disperses dans plusieurs fichiers 142

5
Chapitre 1 : Introduction bash

1. Les shells

Sous Unix, on appelle shell linterprteur de commandes qui fait office d'interface entre
l'utilisateur et le systme dexploitation. Les shells sont des interprteurs : cela signifie que chaque
commande saisie par lutilisateur (ou lue partir dun fichier) est syntaxiquement vrifie puis
excute.

Il existe de nombreux shells qui se classent en deux grandes familles :


- la famille C shell (ex : csh, tcsh)
- la famille Bourne shell (ex : sh, bash, ksh, dash).
zsh est un shell qui contient les caractristiques des deux familles prcdentes. Nanmoins, le
choix dutiliser un shell plutt quun autre est essentiellement une affaire de prfrence
personnelle ou de circonstance. En connatre un, permet daccder aisment aux autres. Lorsque
lon utilise le systme GNU/Linux (un des nombreux systmes de la galaxie Unix), le shell par
dfaut est bash (Bourne Again SHell). Ce dernier a t conu en 1988 par Brian Fox dans le cadre
du projet GNU1. Aujourdhui, les dveloppements de bash sont mens par Chet Ramey.

Un shell possde un double aspect :


- un aspect environnement de travail
- un aspect langage de programmation.

1.1 Un environnement de travail

En premier lieu, un shell doit fournir un environnement de travail agrable et puissant. Par
exemple, bash permet (entre autres) :
- le rappel des commandes prcdentes (gestion de lhistorique) ; cela vite de taper
plusieurs fois la mme commande
- la modification en ligne du texte de la commande courante (ajout, retrait, remplacement
de caractres) en utilisant les commandes ddition de lditeur de texte vi ou emacs
- la gestion des travaux lancs en arrire-plan (appels jobs) ; ceux-ci peuvent tre
dmarrs, stopps ou repris suivant les besoins
- linitialisation adquate de variables de configuration (chane dappel de linterprteur,
chemins de recherche par dfaut) ou la cration de raccourcis de commandes (commande interne
alias).

Illustrons cet ajustement de configuration par un exemple. Le shell permet dexcuter une
commande en mode interactif ou bien par l'intermdiaire de fichiers de commandes (scripts). En
mode interactif, bash affiche lcran une chane dappel (appele galement prompt ou invite),
qui se termine par dfaut par le caractre # suivi dun caractre espace pour ladministrateur
systme (utilisateur root) et par le caractre $ suivi dun caractre espace pour les autres
utilisateurs. Cette chane dappel peut tre relativement longue.

Ex : sanchis@jade:/bin$

1
http://www.gnu.org

6
Celle-ci est constitue du nom de connexion de lutilisateur (sanchis), du nom de la machine sur
laquelle lutilisateur travaille (jade) et du chemin absolu du rpertoire courant de lutilisateur
(/bin). Elle indique que le shell attend que lutilisateur saisisse une commande et la valide en
appuyant sur la touche entre. Bash excute alors la commande puis raffiche la chane dappel.
Si lon souhaite raccourcir cette chane dappel, il suffit de modifier la valeur de la variable
prdfinie du shell PS1 (Prompt Shell 1).

Ex : sanchis@jade:/bin$ PS1='$ '


$ pwd
/bin => pwd affiche le chemin absolu du rpertoire courant
$

La nouvelle chane dappel est constitue par le caractre $ suivi dun caractre espace.

1.2 Un langage de programmation

Les shells ne sont pas seulement des interprteurs de commandes mais galement de vritables
langages de programmation. Un shell comme bash intgre :
- les notions de variable, doprateur arithmtique, de structure de contrle, de fonction,
prsentes dans tout langage de programmation classique, mais aussi
- des oprateurs spcifiques (ex : |, &)

Ex : $ a=5 => affectation de la valeur 5 la variable a


$
$ echo $((a +3 )) => affiche la valeur de lexpression a+3
8
$

Loprateur |, appel tube, est un oprateur caractristique des shells et connecte la sortie dune
commande lentre de la commande suivante.

Ex : $ lpstat -a
HP-LaserJet-2420 acceptant des requtes depuis jeu. 14 mars 2013 10:38:37 CET
HP-LaserJet-P3005 acceptant des requtes depuis jeu. 14 mars 2013 10:39:54 CET
$
$ lpstat -a | wc -l
2
$

La commande unix lpstat permet de connatre les noms et autres informations relatives aux
imprimantes accessibles. La commande unix wc munie de loption l affiche le nombre de lignes
quelle a t en mesure de lire.
En connectant avec un tube la sortie de lpstat -a lentre de la commande wc l, on obtient le
nombre dimprimantes accessibles sur le rseau.

Mme si au fil du temps de nouveaux types de donnes comme les entiers ou les tableaux ont t
introduits dans certains shells, ces derniers manipulent essentiellement des chanes de caractres :
ce sont des langages de programmation orients chanes de caractres. Cest ce qui rend les
shells la fois si puissants et si dlicats utiliser.

Lobjet de ce document est de prsenter de manire progressive les caractristiques de bash


comme langage de programmation.

7
1.3 Atouts et inconvnients des shells

Ltude dun shell tel que bash en tant que langage de programmation possde plusieurs
avantages :
- cest un langage interprt : les erreurs peuvent tre facilement localises et traites ;
dautre part, des modifications de fonctionnalits sont facilement apportes lapplication sans
quil soit ncessaire de recompiler et faire ldition de liens de lensemble
- le shell manipule essentiellement des chanes de caractres : on ne peut donc construire
des structures de donnes complexes laide de pointeurs, ces derniers nexistant pas en shell.
Ceci a pour avantage dviter des erreurs de typage et de pointeurs mal grs. Le dveloppeur
raisonne de manire uniforme en termes de chanes de caractres
- le langage est adapt au prototypage rapide dapplications : les tubes, les substitutions de
commandes et de variables favorisent la construction dune application par assemblage de
commandes prexistantes dans lenvironnement Unix
- cest un langage glu : il permet de connecter des composants crits dans des langages
diffrents. Ils doivent uniquement respecter quelques rgles particulirement simples. Le
composant doit tre capable :
* de lire sur lentre standard,
* daccepter des arguments et options ventuels,
* dcrire ses rsultats sur la sortie standard,
* dcrire les messages derreur sur la sortie standard ddie aux messages derreur.

Cependant, bash et les autres shells en gnral ne possdent pas que des avantages :
- issus dUnix, systme dexploitation crit lorigine par des dveloppeurs pour des
dveloppeurs, les shells utilisent une syntaxe sotrique daccs difficile pour le dbutant
- suivant le contexte, loubli ou lajout dun caractre espace provoque facilement une
erreur de syntaxe
- bash possde plusieurs syntaxes pour implanter la mme fonctionnalit, comme la
substitution de commande ou lcriture dune chane lcran. Cela est principalement d la
volont de fournir une compatibilit ascendante avec le Bourne shell, shell historique des
systmes Unix
- certains caractres spciaux, comme les parenthses, ont des significations diffrentes
suivant le contexte ; en effet, les parenthses peuvent introduire une liste de commandes, une
dfinition de fonction ou bien imposer un ordre dvaluation dune expression arithmtique.
Toutefois, afin de rendre ltude de bash plus aise, nous naborderons pas sa syntaxe de manire
exhaustive ; en particulier, lorsquil existera plusieurs syntaxes pour mettre en oeuvre la mme
fonctionnalit, seule la syntaxe la plus lisible sera prsente, parfois au dtriment de la portabilit
vers les autres shells ou de la compatibilit POSIX.

1.4 Shell utilis

La manire la plus simple de connatre le shell que lon utilise est dexcuter la commande unix
ps qui liste les processus de lutilisateur :

Ex : $ ps
PID TTY TIME CMD
6908 pts/4 00:00:00 bash => linterprteur utilis est bash
6918 pts/4 00:00:00 ps
$

8
Comme il existe plusieurs versions de bash prsentant des caractristiques diffrentes, il est
important de connatre la version utilise. Pour cela, on utilise l'option -version de bash.

Ex : $ bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
Licence GPLv3+ : GNU GPL version 3 ou ultrieure <http://gnu.org/licen
ses/gpl.html>
...
$

La version de bash qui sera utilise est la version 4.2.

2. Syntaxe dune commande

La syntaxe gnrale d'une commande (unix ou de bash) est la suivante :

[ chemin/]nom_cmd [ option ... ] [ argument ... ]

C'est une suite de mots spars par un ou plusieurs blancs. On appelle blanc un caractre tab
(tabulation horizontale) ou un caractre espace.
Un mot est une suite de caractres non blancs. Cependant, plusieurs caractres ont une
signification spciale pour le shell et provoquent la fin d'un mot : ils sont appels mta-caractres
(ex : |, <).

Bash utilise galement des oprateurs (ex : (, ||) et des mots rservs :

! case do done elif else esac


fi for function if in select then
time until while { } [[ ]]

Bash distingue les caractres majuscules des caractres minuscules.

Le nom de la commande est le plus souvent le premier mot.

Une option est gnralement introduite par le caractre tiret (ex : -a) ou dans la syntaxe GNU par
deux caractres tiret conscutifs (ex : --version). Elle prcise un fonctionnement particulier de la
commande.
La syntaxe [ elt ... ] signifie que llment elt est facultatif (introduit par la syntaxe [ elt ]) ou bien
prsent une ou plusieurs fois (syntaxe elt ). Cette syntaxe ne fait pas partie du shell ; elle est
uniquement descriptive (mta-syntaxe).

Les arguments dsignent les objets sur lesquels doit sexcuter la commande.
Ex : ls -l RepC RepD : commande unix ls avec loption l et les arguments RepC et RepD

Lorsque lon souhaite connatre la syntaxe ou les fonctionnalits dune commande cmd (ex : ls ou
bash) il suffit dexcuter la commande man cmd (ex : man bash). Laide en ligne de la
commande cmd devient alors disponible.

9
3. Commandes internes et externes

Le shell distingue deux sortes de commandes :


- les commandes internes
- les commandes externes.

3.1 Commandes internes

Une commande interne est une commande dont le code est implant au sein de linterprteur de
commande. Cela signifie que, lorsquon change de shell courant ou de connexion, par exemple en
passant de bash au C-shell, on ne dispose plus des mmes commandes internes.

Exemples de commandes internes : cd , echo , for , pwd

Sauf dans quelques cas particuliers, linterprteur ne cre pas de processus pour excuter une
commande interne.

Les commandes internes de bash peuvent se dcomposer en deux groupes :


- les commandes simples (ex : cd, echo)
- les commandes composes (ex : for, ((, {).

Commandes simples

Parmi lensemble des commandes internes, echo est lune des plus utilise :

echo :

Cette commande interne affiche ses arguments sur la sortie standard en les sparant par un espace
et va la ligne.

Ex : $ echo bonjour tout le monde


bonjour tout le monde
$

Dans cet exemple, echo est invoque avec quatre arguments : bonjour, tout, le et monde.
On remarquera que les espacements entre les arguments ne sont pas conservs lors de laffichage :
un seul caractre espace spare les mots affichs. En effet, le shell prtraite la commande,
liminant les blancs superflus.
Pour conserver les espacements, il suffit dentourer la chane de caractres par une paire de
guillemets :

Ex : $ echo bonjour tout le monde


bonjour tout le monde
$

On dit que les blancs ont t protgs de l'interprtation du shell.

Pour afficher les arguments sans retour la ligne, on utilise loption -n de echo.

Ex : $ echo -n bonjour
bonjour$

10
La chane dappel $ est crite sur la mme ligne que largument bonjour.

Commandes composes

Les commandes composes de bash sont :

case ... esac if ... fi for ... done select ... done
until ... done while ... done [[ ... ]] ( ... )
{ ... } (( ))

Seuls le premier et le dernier mot de la commande compose sont indiqus. Les commandes
composes sont principalement des structures de contrle.

3.2 Commandes externes

Une commande externe est une commande dont le code se trouve dans un fichier ordinaire. Le
shell cre un processus pour excuter une commande externe. Parmi lensemble des commandes
externes que lon peut trouver dans un systme, nous utiliserons principalement les commandes
unix (ex : ls, mkdir, cat, sleep) et les fichiers shell.

La localisation du code d'une commande externe doit tre connue du shell pour qu'il puisse
excuter cette commande. A cette fin, bash utilise la valeur de sa variable prdfinie PATH.
Celle-ci contient une liste de chemins spars par le caractre : (ex : /bin:/usr/bin). Par exemple,
lorsque lutilisateur lance la commande unix cal, le shell est en mesure de lexcuter et dafficher
le calendrier du mois courant car le code de cal est situ dans le rpertoire /usr/bin prsent dans
PATH.

Ex : $ cal
Fvrier 2014
di lu ma me je ve sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28

Remarque : pour connatre le statut dune commande, on utilise la commande interne type.

Ex : $ type t sleep
file => sleep est une commande externe
$ type t echo
builtin => echo est une commande interne du shell
$

4. Modes dexcution dune commande

Deux modes dexcution peuvent tre distingus :


- lexcution squentielle
- lexcution en arrire-plan.

11
4.1 Excution squentielle

Le mode dexcution par dfaut dune commande est lexcution squentielle : le shell lit la
commande entre par lutilisateur, lanalyse, la prtraite et si elle est syntaxiquement correcte,
lexcute.
Une fois lexcution termine, le shell effectue le mme travail avec la commande suivante.
Lutilisateur doit donc attendre la fin de lexcution de la commande prcdente pour que la
commande suivante puisse tre excute : on dit que lexcution est synchrone.

Si on tape la suite de commandes :


sleep 5 entre date entre
o entre dsigne la touche entre, lexcution de date dbute aprs que le dlai de 5 secondes se
soit coul.

Pour lancer lexcution squentielle de plusieurs commandes sur la mme ligne de commande, il
suffit de les sparer par un caractre ;

Ex : $ cd /tmp ; pwd; echo bonjour; cd ; pwd


/tmp => affiche par lexcution de pwd
bonjour => affiche par lexcution de echo bonjour
/home/sanchis => affiche par lexcution de pwd
$

Pour terminer lexcution dune commande lance en mode synchrone, on appuie simultanment
sur les touches CTRL et C (notes control-C ou ^C).
En fait, la combinaison de touches approprie pour arrter lexcution dune commande en mode
synchrone est indique par la valeur du champ intr lorsque la commande unix stty est lance :

Ex : $ stty -a
speed 38400 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?;
. . .
$

Supposons que la commande unix cat soit lance sans argument, son excution semblera fige
un utilisateur qui dbute dans lapprentissage dun systme Unix. Il pourra utiliser la combinaison
de touches mentionne prcdemment pour terminer lexcution de cette commande.

Ex : $ cat
^C
$

4.2 Excution en arrire-plan

Lexcution en arrire-plan permet un utilisateur de lancer une commande et de rcuprer


immdiatement la main pour lancer en parallle la commande suivante (paralllisme logique).
On utilise le caractre & pour lancer une commande en arrire-plan.

Dans lexemple ci-dessous, la commande sleep 5 (suspendre lexcution pendant 5 secondes) est
lance en arrire-plan. Le systme a affect le numro didentification 696 (galement appel pid)
au processus correspondant tandis que bash a affect un numro de travail (ou numro de job)

12
gal 1 et affich [1]. Lutilisateur peut, en parallle, excuter dautres commandes (dans cet
exemple, il sagit de la commande unix ps). Lorsque la commande en arrire-plan se termine, le
shell le signale l'utilisateur aprs que ce dernier ait appuy sur la touche entre.

Ex : $ sleep 5 &
[1] 696
$ ps
PID TTY TIME CMD
683 pts/0 00:00:00 bash
696 pts/0 00:00:00 sleep
697 pts/0 00:00:00 ps
$ => lutilisateur a appuy sur la touche entre mais sleep ntait pas termine
$ => lutilisateur a appuy sur la touche entre et sleep tait termine
[1]+ Done sleep 5
$

Ainsi, outre la gestion des processus spcifique Unix, bash introduit un niveau supplmentaire
de contrle de processus. En effet, bash permet de stopper, reprendre, mettre en arrire-plan un
processus, ce qui ncessite une identification supplmentaire (numro de job) non fournie par le
systme dexploitation mais par bash.
Lexcution en arrire-plan est souvent utilise lorsquune commande est gourmande en temps
CPU (ex : longue compilation dun programme).

5. Commentaires

Un commentaire dbute avec le caractre # et se termine avec la fin de la ligne. Un commentaire


est ignor par le shell.

Ex : $ echo bonjour # lami


bonjour
$ echo coucou #l ami
coucou
$ # echo coucou
$

Pour que le caractre # soit reconnu en tant que dbut de commentaire, il ne doit pas tre insr
lintrieur dun mot ou terminer un mot.

Ex : $ echo il est#10 heures


il est#10 heures
$
$ echo bon# jour
bon# jour
$

6. Fichiers shell

Lorsquun traitement ncessite lexcution de plusieurs commandes, il est prfrable de les


sauvegarder dans un fichier plutt que de les retaper au clavier chaque fois que le traitement doit
tre lanc. Ce type de fichier est appel fichier de commandes ou fichier shell ou encore script
shell.

13
Exercice 1 :

1.) A laide dun diteur de texte, crer un fichier premier contenant les lignes
suivantes :

#!/bin/bash
# premier

echo -n "La date du jour est: "


date

La notation #! en premire ligne d'un fichier interprt prcise au shell courant quel
interprteur doit tre utilis pour excuter le programme (dans cet exemple, il sagit
de /bin/bash).
La deuxime ligne est un commentaire.

2.) Vrifier le contenu de ce fichier.

Ex : $ cat premier
#!/bin/bash
# premier

echo -n "La date du jour est : "


date
$

3.) Pour lancer lexcution dun fichier shell fich, on peut utiliser la commande :
bash fich

Ex : $ bash premier
la date du jour est : jeudi 27 fvrier 2014, 17:34:25 (UTC+0100)
$

4.) Lorsque lon est un utilisateur sans privilge particulier ( la diffrence de


lutilisateur root), il est plus simple de lancer lexcution dun programme shell en
tapant directement son nom, comme on le ferait pour une commande unix ou une
commande interne. Pour que cela soit ralisable, deux conditions doivent tre
remplies :
- lutilisateur doit possder les permissions r (lecture) et x (excution) sur le
fichier shell
- le rpertoire dans lequel se trouve le fichier shell doit tre prsent dans la
liste des chemins contenue dans PATH.

Ex : $ ls -l premier
-rw-r--r-- 1 sanchis sanchis 63 fvr. 26 16:46 premier
$

Seule la permission r est possde par lutilisateur.


Pour ajouter la permission x au propritaire du fichier fich, on utilise la commande :
chmod u+x fich

14
Ex : $ chmod u+x premier
$
$ ls -l premier
-rwxr--r-- 1 sanchis sanchis 63 fvr. 26 16:46 premier

Si on excute premier en ltat, une erreur dexcution se produit.

Ex : $ premier
premier: commande introuvable => Problme !
$

Cette erreur se produit car bash ne sait pas o se trouve le fichier premier.

Ex : $ echo $PATH => affiche la valeur de la variable PATH


/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
$
$ pwd
/home/sanchis
$

Le rpertoire dans lequel se trouve le fichier premier (rpertoire /home/sanchis)


nest pas prsent dans la liste de PATH. Pour que le shell puisse trouver le fichier
premier, il suffit de mentionner le chemin permettant daccder celui-ci.

Ex : $ ./premier
la date du jour est : jeudi 27 fvrier 2014, 17:39:27 (UTC+0100)
$

Pour viter davoir saisir systmatiquement ce chemin, il suffit de modifier la


valeur de PATH en y incluant, dans notre cas, le rpertoire courant (.).

Ex : $ PATH=$PATH:. => ajout du rpertoire courant dans PATH


$
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:.
$
$ premier
la date du jour est : jeudi 27 fvrier 2014, 17:41:21 (UTC+0100)
$

Remarque : on vitera dappeler test un script shell. En effet, test est une commande interne de
bash qui, excute sans argument, ne produit aucune sortie.
Lorsquune commande interne et un fichier shell portent le mme nom, bash
excute la commande interne.

Ex : $ cat test => contenu dun script shell appel test


#!/bin/bash
# @(#) test

echo coucou !

15
$ ls -l test
-rwxr--r-- 1 sanchis sanchis 40 fvr. 26 18:46 test
$
$ test => excution de la commande interne test alors que
$ => lutilisateur pensait avoir lanc le shell script test !
$
$ ./test => excution du shell script
coucou !
$

Exercice 2 : En utilisant les commandes appropries, crire un programme shell repcour qui
affiche le nom de connexion de l'utilisateur et le chemin absolu de son rpertoire
courant de la manire suivante :

Ex : $ repcour
mon nom de connexion est : sanchis
mon repertoire courant est : /home/sanchis
$

16
Chapitre 2 : Substitution de paramtres

Dans la terminologie du shell, un paramtre dsigne toute entit pouvant contenir une valeur.

Le shell distingue trois classes de paramtres :


les variables, identifies par un nom
Ex : a , PATH
les paramtres de position, identifis par un numro
Ex : 0 , 1 , 12
les paramtres spciaux, identifis par un caractre spcial
Ex : # , ? , $

Le mode daffectation d'une valeur est spcifique chaque classe de paramtres. Suivant celle-ci,
laffectation sera effectue par lutilisateur, par bash ou bien par le systme. Par contre, pour
obtenir la valeur d'un paramtre, on placera toujours le caractre $ devant sa rfrence, et cela
quelle que soit sa classe.

Ex : $ echo $PATH => affiche la valeur de la variable PATH


/usr/sbin:/usr/bin:/sbin:/bin:.:/home/sanchis/bin
$ echo $$ => affiche la valeur du paramtre spcial $
17286
$

1. Variables
Une variable est identifie par un nom, c'est--dire une suite de lettres, de chiffres ou de caractres
espace soulign ne commenant pas par un chiffre. Les lettres majuscules et minuscules sont
diffrencies.

Les variables peuvent tre classes en trois groupes :


- les variables utilisateur (ex : a, valeur)
- les variables prdfinies du shell (ex : PS1, PATH, REPLY, IFS, HOME)
- les variables prdfinies de commandes unix (ex : TERM).
En gnral, les noms des variables utilisateur sont en lettres minuscules tandis que les noms des
variables prdfinies (du shell ou de commandes unix) sont en majuscules.

Lutilisateur peut affecter une valeur une variable en utilisant


- loprateur daffectation =
- la commande interne read.

Affectation directe

Syntaxe : nom=[valeur] [ nom=[valeur] ... ]

Il est impratif que le nom de la variable, le symbole = et la valeur affecter ne forment quune
seule chane de caractres.
Plusieurs affectations peuvent tre prsentes dans la mme ligne de commande.

17
Ex : $ x=coucou y=bonjour => la variable x contient la chane de caractres coucou
$ => la variable y contient la chane bonjour

ATTENTION : les syntaxes daffectation errones les plus frquentes contiennent

- un ou plusieurs caractres espace entre le nom de la variable et le symbole =.

Ex : $ b =coucou
b : commande introuvable
$

Le shell interprte b comme une commande excuter ; ne la trouvant pas, il signale une
erreur.

- un ou plusieurs caractres espace entre le symbole = et la valeur de la variable.

Ex : $ y= coucou
coucou : commande introuvable
$

La chane coucou est interprte comme la commande excuter.

Lorsque le shell rencontre la chane $x, il la remplace textuellement par la valeur de la variable x,
c.--d. coucou ; en dautres termes, la chane $x est remplace par la chane coucou. Dans
lexemple ci-dessous, la commande finalement excute par bash est : echo x est coucou

Ex : $ echo x est $x
x est coucou
$

Il est important de remarquer que le nom dun paramtre et la valeur de ce paramtre ne se


dsignent pas de la mme manire.

Ex : $ x=$x$y => x : contenant, $x : contenu


$ echo $x
coucoubonjour
$

La nouvelle valeur de la variable x est constitue de la valeur prcdente de x (chane coucou)


laquelle a t colle (concatne) la valeur de la variable y (chane bonjour).

Lorsque lon souhaite effectuer ce type de concatnation, il est possible dutiliser loprateur +=
de bash.

Ex : $ x=coucou y=bonjour
$ x+=$y
$ echo $x
coucoubonjour
$

Affectation par lecture

Elle seffectue l'aide de la commande interne read. Celle-ci lit une ligne entire sur lentre
standard.

18
Syntaxe : read [ var1 ... ]

Ex : $ read a b
bonjour Monsieur => chanes saisies par lutilisateur et enregistres
$ => respectivement dans les variables a et b
$ echo $b
Monsieur
$

Lorsque la commande interne read est utilise sans argument, la ligne lue est enregistre dans la
variable prdfinie du shell REPLY.

Ex : $ read
bonjour tout le monde
$
$ echo $REPLY
bonjour tout le monde
$

Loption p de read affiche une chane dappel avant deffectuer la lecture ; la syntaxe utiliser
est : read p chane_d_appel [ var ]

Ex : $ read -p "Entrez votre prenom : " prenom


Entrez votre prenom : Eric
$
$ echo $prenom
Eric
$

Remarques sur la commande interne read

- sil y a moins de variables que de mots dans la ligne lue, le shell affecte le premier mot
la premire variable, le deuxime mot la deuxime variable, etc., la dernire variable reoit tous
les mots restants.

Ex : $ read a b c
un bon jour coucou
$
$ echo $a
un
$ echo $c
jour coucou
$

- sil y a davantage de variables que de mots dans la ligne lue, chaque variable reoit un
mot et aprs puisement de ces derniers, les variables excdentaires sont vides (c.--d. initialises
la valeur null).

Ex : $ read a b
un
$
$ echo $a
un
$
$ echo $b
=> valeur null
$

19
Exercice 1 : Ecrire un programme shell deuxfois qui affiche le message "Entrez un mot : ", lit le
mot saisi par l'utilisateur puis affiche ce mot deux fois sur la mme ligne.

Ex : $ deuxfois
Entrez un mot : toto
toto toto
$

Exercice 2 : Ecrire un programme shell untrois qui demande l'utilisateur de saisir une suite de
mots constitue d'au moins trois mots et qui affiche sur la mme ligne le premier et
le troisime mot saisis.

Ex : $ untrois
Entrez une suite de mots : un petit coucou de Rodez
un coucou
$

Variable en lecture seule

Pour dfinir une variable dont la valeur ne doit pas tre modifie (appele constante dans dautres
langages de programmation), on utilise la syntaxe :

declare r nom=valeur [ nom=valeur ]

Ex : $ declare -r mess=bonjour
$

On dit que la variable mess possde lattribut r.

Une tentative de modification de la valeur dune constante provoque une erreur.

Ex : $ mess=salut
bash: mess : variable en lecture seule
$

Pour connatre la liste des constantes dfinies : declare r

Ex : $ declare -r
declare -r
BASHOPTS="checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fign
ore:histappend:interactive_comments:progcomp:promptvars:sourcepath"
declare -ir BASHPID
declare -r BASH_COMPLETION="/etc/bash_completion"
declare -r BASH_COMPLETION_COMPAT_DIR="/etc/bash_completion.d"
declare -r BASH_COMPLETION_DIR="/etc/bash_completion.d"
declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="24" [3]="1"
[4]="release" [5]="i686-pc-linux-gnu")'
declare -ir EUID="1000"
declare -ir PPID="1864"
declare -r
SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-
comments:monitor"
declare -ir UID="1000"
declare -r mess="bonjour"
$

20
Plusieurs constantes sont prdfinies dont le tableau BASH_VERSINFO (attribut a) et les
entiers EUID, PPID et UID (attribut i).

Variables denvironnement

Par dfaut, lorsquun utilisateur dfinit une variable var, celle-ci reste locale linterprteur bash
qui la cre. Cela signifie par exemple que si lutilisateur lance lexcution dun deuxime shell,
celui-ci naura pas accs la variable var.

Ex : $ a=coucou => dfinition de la variable locale a


$
$ echo $a
coucou => la valeur de a est accessible
$
$ bash => cration dun shell bash, fils de linterprteur prcdent, qui
$ => interprtera les futures commandes saisies
$ ps
PID TTY TIME CMD
9918 pts/1 00:00:00 bash => bash pre
9933 pts/1 00:00:00 bash => bash fils
9948 pts/1 00:00:00 ps
$
$
$ echo $a
=> la variable a est inconnue pour le shell bash fils
$
$ exit => terminaison du shell fils
exit
$
$ ps
PID TTY TIME CMD
9918 pts/1 00:00:00 bash => bash pre
9949 pts/1 00:00:00 ps
$
$ echo $a
coucou
$

En fait, lensemble des variables accessibles un interprteur (ou plus gnralement un


processus) peut se dcomposer en deux classes :
- les variables locales (comme la variable a de lexemple prcdent) : elles disparaissent
lorsque linterprteur (ou le processus) se termine
- les variables denvironnement : celles-ci ont la particularit dtre automatiquement
transmises sa descendance, c.--d. copies, tous les shells fils (ou processus fils) quil crera
dans le futur.

Des exemples de variables denvironnement usuelles sont PATH et HOME.

Pour crer une variable denvironnement ou faire devenir variable denvironnement une variable
dj existante, on utilise la commande interne export.

Ex : $ a=coucou
$
$ b=bonjour => dfinition de la variable locale b
$ export b => la variable b devient une variable denvironnement

21
$
$ export c=bonsoir => dfinition de la variable denvironnement c
$
$ bash => cration dun shell fils
$
$ echo $a
=> la variable a est inconnue
$ echo $b
bonjour
$
$ echo $c
bonsoir => les variables b et c sont connues du shell fils
$
$ exit => fin du shell fils
exit
$

La commande interne set sans argument affiche (entre autres) toutes les variables associes un
processus alors que la commande unix env affiche uniquement les variables d'environnement.

Ex : $ set
. . .
a=coucou
b=bonjour
c=bonsoir
. . .
$
$ env
. . . => la variable a est absente de lenvironnement
b=bonjour
c=bonsoir
. . .
$

La transmission des variables denvironnement est unidirectionnelle : du processus pre vers le(s)
processus fils. Si un processus fils modifie la valeur dune variable denvironnement, seule sa
copie locale en sera affecte ; cette modification sera transparente pour son processus pre.

Ex : $ export a=coucou
$
$ bash
$ echo $a
coucou
$
$ a=bonsoir => modification de la variable denvironnement a dans le shell fils
$ echo $a
bonsoir
$
$ exit
exit
$
$ echo $a
coucou => la valeur na pas t modifie dans le shell pre
$

22
2. Paramtres de position et paramtres spciaux
2.1 Paramtres de position

Un paramtre de position est rfrenc par un ou plusieurs chiffres : 8 , 0 , 23

Lassignation de valeurs des paramtres de position seffectue :


- soit laide de la commande interne set
- soit lors de lappel dun fichier shell ou dune fonction shell.

Attention : on ne peut utiliser ni le symbole =, ni la commande interne read pour


affecter directement une valeur un paramtre de position.

Ex : $ 23=bonjour
23=bonjour : commande introuvable
$
$ read 4
aa
bash: read: 4 : identifiant non valable
$

Commande interne set :

La commande interne set affecte une valeur un ou plusieurs paramtres de position en


numrotant ses arguments suivant leur position. La numrotation commence 1.

Syntaxe : set arg1 ...

Ex : $ set alpha beta gamma => alpha est la valeur du paramtre de position 1, beta la
$ => valeur du deuxime paramtre de position et gamma
$ => la valeur du paramtre de position 3

Pour obtenir la valeur dun paramtre de position, il suffit de placer le caractre $ devant son
numro ; ainsi, $1 permet dobtenir la valeur du premier paramtre de position, $2 la valeur du
deuxime et ainsi de suite.

Ex : $ set ab be ga => numrotation des mots ab, be et ga


$
$ echo $3 $2
ga be
$
$ echo $4

Tous les paramtres de position sont rinitialiss ds que la commande interne set est utilise avec
au moins un argument.
Ex : $ set coucou
$ echo $1
coucou
$ echo $2
=> les valeurs be et ga prcdentes ont disparues
$

23
La commande interne set -- rend indfinie la valeur des paramtres de position pralablement
initialiss.

Ex : $ set alpha beta


$ echo $1
alpha
$
$ set --
$ echo $1
=> les valeurs alpha et beta sont perdues
$

Variable prdfinie IFS et commande interne set

La variable prdfinie IFS du shell contient les caractres sparateurs de mots. Par dfaut, ce sont
les caractres espace, tabulation et interligne. Linitialisation de IFS est effectue par bash.

En modifiant judicieusement la valeur de IFS, il est possible avec la commande interne set de
dcomposer une chane de caractres en plusieurs mots et de les associer des paramtres de
position.

Ex : $ a=Jean:12:Rodez => chane compose de 3 champs spars par le caractre :


$ svIFS=$IFS => sauvegarde de la valeur courante de IFS
$ IFS=: => le caractre : devient un sparateur
$ set $a => substitution, dcomposition en mots puis numrotation
$ IFS=$svIFS => restitution de la valeur originelle de IFS
$ echo "Prenom : $1, Age : $2, Ville : $3"
Prenom : Jean, Age : 12, Ville : Rodez
$

Remarques :

- utilise sans argument, set a un comportement diffrent : elle affiche, entre autres, la
(longue) liste des noms et valeurs des variables dfinies.

Ex : $ set | more
BASH=/bin/bash
. . .
$

- si la valeur du premier argument de set commence par un caractre - ou +, une erreur


se produit. En effet, les options de cette commande interne commencent par un de ces deux
caractres.
Pour viter que ce type derreur ne se produise, on utilise la syntaxe : set -- arg ...

Ex : $ a=+qui
$ set $a
bash: set: +q : option non valable
set : utilisation : set [-abefhkmnptuvxBCHP] [-o option-name] [--]
[arg ...]
$ set -- $a
$
$ echo $1
+qui
$

24
2.2 Paramtres spciaux

Un paramtre spcial est rfrenc par un caractre spcial. Laffectation dune valeur un
paramtre spcial est effectue par le shell. Pour obtenir la valeur dun paramtre spcial, il suffit
de placer le caractre $ devant le caractre spcial qui le reprsente.

Un paramtre spcial trs utilis est le paramtre # ( ne pas confondre avec le dbut dun
commentaire). Celui-ci contient le nombre de paramtres de position ayant une valeur.

Ex : $ set a b c
$
$ echo $# => affichage de la valeur du paramtre spcial #
3 => il y a 3 paramtres de position ayant une valeur
$

Exercice 3 : Ecrire un programme shell nbmots qui demande l'utilisateur de saisir une suite
quelconque non vide de mots puis affiche le nombre de mots saisis.

Ex : $ nbmots
Entrez une suite de mots : un deux trois quatre cinq
5 => 5 mots ont t saisis
$

2.3 Commande interne shift

La commande interne shift dcale la numrotation des paramtres de position ayant une valeur.

Syntaxe : shift [ n ]

Elle renomme le n+1 me paramtre de position en paramtre de position 1, le n+2 me paramtre de


position en paramtre de position 2, etc. :
(n+1) => 1 , (n+2) => 2 , etc.
Une fois le dcalage effectu, le paramtre spcial # est mis jour.

Ex : $ set a b c d e
=> 1 2 3 4 5
$ echo $1 $2 $#
a b 5
$
$ shift 2
=> abcde les mots a et b sont devenus inaccessibles
=> 123
$ echo $1 $3
c e
$ echo $#
3
$

La commande interne shift sans argument est quivalente shift 1.

25
Remarque : shift ne modifie pas la valeur du paramtre de position 0 qui possde une
signification particulire.

2.4 Paramtres de position et fichiers shell

Dans un fichier shell, les paramtres de position sont utiliss pour accder aux valeurs des
arguments qui ont t passs lors de son appel : cela signifie quau sein du fichier shell, les
occurrences de $1 sont remplaces par la valeur du premier argument, celles de $2 par la valeur du
deuxime argument, etc. Le paramtre spcial $# contient le nombre darguments passs lors de
lappel.
Le paramtre de position 0 contient le nom complet du programme shell qui sexcute.

Soit le programme shell copie :


#!/bin/bash
# @(#) copie

echo "Nom du programme : $0"


echo "Nb d'arguments : $#"
echo "Source : $1"
echo "Destination : $2"
cp $1 $2

Pour excuter ce fichier shell :

Ex : $ chmod u+x copie


$
$ copie /etc/passwd X
Nom du programme : ./copie
Nb d'arguments : 2
Source : /etc/passwd
Destination : X
$

Dans le fichier copie, chaque occurrence de $1 a t remplace par la chane de caractres


/etc/passwd, celles de $2 par X.

Exercice 4 : Ecrire un programme shell cp2fois prenant trois arguments : le premier dsigne le
nom du fichier dont on veut copier le contenu dans deux fichiers dont les noms sont
passs comme deuxime et troisime arguments. Aucun cas d'erreur ne doit tre
considr.

Lorsque la commande interne set est utilise lintrieur dun programme shell, la syntaxe $1
possde deux significations diffrentes : $1 comme premier argument du programme shell, et $1
comme premier paramtre de position initialis par set au sein du fichier shell.

Exemple : programme shell ecrase_arg


---------------
# !/bin/bash

echo '$1' est $1 => la chane $1 est remplace par le premier argument
set hello => set crase la valeur prcdente de $1
echo '$1' est $1
---------------

26
Ex : $ ecrase_arg bonjour coucou salut
$1 est bonjour
$1 est hello
$

2.5 Paramtres spciaux * et @

Les paramtres spciaux @ et * contiennent tous deux la liste des valeurs des paramtres de
position initialiss.

Ex : $ set un deux trois quatre


$
$ echo $*
un deux trois quatre
$
$ echo $@
un deux trois quatre
$

Ces deux paramtres spciaux ont des valeurs distinctes lorsque leur rfrence est place entre des
guillemets ("$*" et "$@") :

"$*" est remplace par "$1 $2 ... "


"$@" est remplace par "$1" "$2" ...

Ex : $ set bonjour "deux coucou" salut => trois paramtres de position sont initialiss
$
$ set "$*" => est quivalent : set bonjour deux coucou salut
$
$ echo $#
1
$
$ echo $1
bonjour deux coucou salut
$

La syntaxe "$*" traite lensemble des paramtres de position initialiss comme une unique chane
de caractres.

Inversement, la syntaxe "$@" produit autant de chanes que de paramtres de positions initialiss.

Ex : $ set bonjour "deux coucou" salut => trois paramtres de position initialiss
$
$
$ set "$@" => est quivalent : set bonjour deux coucou salut
$
$ echo $#
3
$ echo $2
deux coucou => lintgrit de la chane a t prserve
$

Lorsque lon souhaite mentionner dans une commande la liste des paramtres de position
initialiss, il est conseill dutiliser la syntaxe "$@" car elle protge les ventuels caractres
espace prsents dans ces derniers.

27
Exercice 5 : Ecrire un programme shell cx prenant en arguments un nombre quelconque de
noms dentres1 et ajoute leur propritaire la permission x.

Ex : $ ls -l
total 12
-rwxr--r-- 1 sanchis sanchis 15 nov. 2 2010 cx
-rw-r--r-- 1 sanchis sanchis 58 nov. 2 2010 script.bsh
-rw-r--r-- 1 sanchis sanchis 135 nov. 2 2010 une commande
$
$ cx "une commande" script.bsh
$
$ ls -l
total 12
-rwxr--r-- 1 sanchis sanchis 15 nov. 2 2010 cx
-rwxr--r-- 1 sanchis sanchis 58 nov. 2 2010 script.bsh
-rwxr--r-- 1 sanchis sanchis 135 nov. 2 2010 une commande
$

3. Suppression des ambiguts


Pour viter les ambiguts dans linterprtation des rfrences de paramtres, on utilise la syntaxe
${paramtre}.

Ex : $ x=bon
$ x1=jour
$ echo $x1 => valeur de la variable x1
jour
$ echo ${x}1 => pour concatner la valeur de la variable x la chane 1
bon1
$

Ex : $ set un deux trois quatre cinq six sept huit neuf dix onze douze
$ echo $11
un1
$
$ echo ${11} => pour obtenir la valeur du onzime paramtre de position
onze
$

4. Paramtres non dfinis


Trois cas peuvent se prsenter lorsque le shell doit valuer un paramtre :
- le paramtre nest pas dfini,
- le paramtre est dfini mais ne possde aucune valeur (valeur vide),
- le paramtre possde une valeur non vide.

Lorsque loption nounset de la commande interne set est positionne ltat on (commande
set -o nounset), bash affiche un message derreur quand il doit valuer un paramtre non dfini.

1
On appelle entre tout objet pouvant tre rfrenc dans un rpertoire : fichier ordinaire, rpertoire, fichier spcial,
etc.

28
Ex : $ set -o nounset => option nounset ltat on
$
$ echo $e => variable utilisateur e non dfinie,
bash: e : variable sans liaison => message derreur !
$
$ set -- => paramtres de position sont rinitialiss
$ echo $1
bash: $1 : variable sans liaison
$
$ d= => d : variable dfinie mais vide
$
$ echo $d
=> valeur null, pas derreur
$

La prsence de paramtres non dfinis ou dfinis mais vides dans une commande peut mener son
excution lchec. Afin de traiter ce type de problme, bash fournit plusieurs mcanismes
supplmentaires de substitution de paramtres. Lun deux consiste associer au paramtre une
valeur ponctuelle lorsquil est non dfini ou bien dfini vide. La syntaxe utiliser est la suivante :
${paramtre:-chane}

Ex : $ set -o nounset
$
$ ut1=root => ut1 dfinie et non vide
$ ut2= => ut2 dfinie et vide
$
$ echo $ut1
root
$
$ echo $ut2

$ echo $1
bash: $1 : variable sans liaison => paramtre de position 1 non dfini
$

Avec la syntaxe mentionne ci-dessus, il est possible dassocier temporairement une valeur par
dfaut aux trois paramtres.

Ex : $ echo ${ut1:-sanchis}
root => ut1 tant dfinie non vide, sa valeur est utilise
$
$ echo ${ut2:-sanchis} => ut2 est dfinie et vide, la valeur de remplacement est
sanchis => utilise
$
$ echo ${1:-sanchis}
sanchis => le premier paramtre de position est non dfini, la
$ => valeur de remplacement est utilise

Cette association ne dure que le temps dexcution de la commande.

Ex : $ echo $1
bash: $1 : variable sans liaison => le paramtre est redevenu indfini
$

La commande set +o nounset positionne loption nounset ltat off : le shell traite les
paramtres non dfinis comme des paramtres vides.

29
Ex : $ set +o nounset => option nounset ltat off
$
$ echo $e => variable e non dfinie,
=> aucune erreur signale
$
$ echo $2
=> aucune erreur signale
$
$ f= => f : variable dfinie vide
$ echo $f

5. Suppression de variables
Pour rendre indfinies une ou plusieurs variables, on utilise la commande interne unset.

Syntaxe : unset var [ var1 . . . ]

Ex : $ a=coucou => la variable a est dfinie


$ echo $a
coucou
$ unset a => la variable a est supprime
$
$ set -o nounset => pour afficher le message derreur
$ echo $a
bash: a : variable sans liaison
$

Une variable en lecture seule ne peut tre supprime par unset.

Ex : $ declare -r a=coucou => dfinition de la constante a


$ echo $a
coucou
$ unset a
bash: unset: a : unset impossible : variable est en lecture seule
$

6. Indirection
Bash offre la possibilit dobtenir la valeur dune variable v1 dont le nom est contenu (en tant que
valeur "v1") dans une autre variable var. Il suffit pour cela dutiliser la syntaxe de substitution
suivante : ${!var}.

Ex : $ var=v1
$ v1=un
$
$ echo ${!var}
un
$

Ce mcanisme, appel indirection, permet daccder de manire indirecte et par consquent de


faon plus souple, la valeur dun deuxime objet.

30
Le fichier shell indir illustre cette souplesse en montrant comment il est possible de crer la
vole le nom de la variable qui contient linformation souhaite.

#!/bin/bash
# @(#) indir

agePierre=10
ageJean=20

read -p "Quel age (Pierre ou Jean) voulez-vous connaitre ? " prenom

rep=age$prenom # construction du nom de la variable


echo ${!rep}

Deux variables agePierre et ageJean contiennent respectivement lge des personnes Pierre et
Jean. Le programme demande lutilisateur de saisir le prnom dont il souhaite connatre lge,
construit le nom de la variable contenant lge demand puis affiche ce dernier.

Ex : $ indir
Quel age (Pierre ou Jean) voulez-vous connaitre ? Pierre
10
$
$ indir
Quel age (Pierre ou Jean) voulez-vous connaitre ? Jean
20
$

Ce mcanisme sapplique galement aux deux autres types de paramtres : les paramtres de
position et les paramtres spciaux.

Ex : $ a=un
$ b=deux
$ c=trois
$
$ set a b c => $1, $2 et $3 ont respectivement pour valeur les chanes
$ => "a", "b", "c"
$ echo $2
b
$
$ echo ${!2} => la valeur de $2 est la chane "b" qui est le nom dune variable
deux => contenant la valeur "deux"
$
$ echo ${!3}
trois
$
$ echo ${!#} => la valeur de $# est 3 et la valeur de $3 est la chane "c"
c
$

Remarque : il ne faut pas confondre deux syntaxes trs proches fournies par bash mais qui
correspondent deux mcanismes totalement diffrents :
${!param} et ${!var*}
La premire syntaxe sera interprte par le shell comme une indirection, tandis que
la deuxime sera remplace par les noms de variables qui commencent par var.

31
Ex : $ a=alpha
$ x=beta
$ age=20
$
$ echo ${!a*} => ${!a*} sera remplace par les noms de
a age => variables qui commencent par a
$

32
Chapitre 3 : Substitution de commandes

1. Prsentation
Syntaxe : $( cmd )

Une commande cmd entoure par une paire de parenthses () prcdes d'un caractre $ est
excute par le shell puis la chane $( cmd ) est remplace par les rsultats de la commande cmd
crits sur la sortie standard, cest dire lcran1. Ces rsultats peuvent alors tre affects une
variable ou bien servir initialiser des paramtres de position.

Ex : $ pwd
/home/sanchis => rsultat crit par pwd sur sa sortie standard
$ repert=$(pwd) => la chane /home/sanchis remplace la chane $(pwd)
$
$ echo mon repertoire est $repert
mon repertoire est /home/sanchis
$

Exercice 1 : En utilisant la substitution de commande, crire un fichier shell mach affichant :


"Ma machine courante est nomdelamachine"

Ex : $ mach
Ma machine courante est jade
$

Lorsque la substitution de commande est utilise avec la commande interne set, lerreur suivante
peut se produire :

$ set $( ls -l .bashrc)
bash: set: -w : option non valable
set : utilisation : set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg
...]
$ ls -l .bashrc
-rw-r--r-- 1 sanchis sanchis 3486 mai 18 2013 .bashrc
$

Le premier mot issu de la substitution commence par un caractre tiret : la commande interne set
l'interprte comme une suite doptions, ce qui provoque une erreur. Pour rsoudre ce type de
problme, on double le caractre tiret [cf. Chapitre 2, 2.1].

Ex : $ set -- $(ls -l .bashrc)


$
$ echo $1
-rw-r--r--
$

1
Il existe pour la substitution de commande une syntaxe plus ancienne `cmd ` (deux caractres accent grave
entourent la commande cmd), utiliser lorsque se posent des problmes de portabilit.

33
Exercice 2 : Ecrire un programme shell taille qui prend un nom de fichier en argument et
affiche sa taille. On ne considre aucun cas d'erreur.

Ex : $ ls -l .bashrc
-rw-r--r-- 1 sanchis sanchis 3486 mai 18 2013 .bashrc
$
$ taille .bashrc
3486
$

Plusieurs commandes peuvent tre prsentes entre les parenthses.

Ex : $ pwd ; whoami
/home/sanchis
sanchis
$
$ set $(pwd ; whoami)
$
$ echo $2: $1
sanchis: /home/sanchis
$

Exercice 3 : A l'aide de la commande unix date, crire un programme shell jour qui affiche le
jour courant du mois.

Ex : $ date
lundi 24 mars 2014, 09:08:02 (UTC+0100)
$
$ jour
24
$

Exercice 4 : a) Ecrire un programme shell heure1 qui affiche l'heure sous la forme :
heures:minutes:secondes

Ex : $ heure1
09:11:40
$

b) Ecrire un programme shell heure qui n'affiche que les heures et minutes.
On pourra utiliser la variable prdfinie IFS du shell [cf. Chapitre 2, 2.1].

Ex : $ heure
09:11
$

Exercice 5 : Ecrire un programme shell uid qui affiche l'uid de l'utilisateur. On utilisera la
commande unix id, la commande interne set et la variable prdfinie IFS.

Les substitutions de commandes peuvent tre imbriques.

34
Ex : $ ls .gnome2
keyrings nautilus-scripts
$
$ set $( ls $(pwd)/.gnome2 )
$ echo $# => nombre d'entres visibles2 du rpertoire .gnome2
2
$

Plusieurs sortes de substitutions (de commandes, de variables) peuvent tre prsentes dans la
mme commande.

Ex : $ read rep
.gnome2
$ set $( ls $( pwd )/$rep ) => substitutions de deux commandes et d'une
$ => variable
$ echo $2
nautilus-scripts
$

La substitution de commande est utile pour capter les rsultats crits par un fichier shell lors de
son excution.

Ex : $ jour => [cf. Exercice 3]


24
$
$ resultat=$(jour) => la variable resultat contient la chane 24
$

En utilisant ce mcanisme, un processus pre peut rcuprer les modifications locales effectues
par un processus fils sur son propre environnement [cf. Chapitre 2, 1.3].

Ex : $ cat modifLOGNAME
#!/bin/bash

LOGNAME=Eric # modification de la variable denvironnement


echo $LOGNAME
$

Le fichier shell modifLOGNAME modifie et affiche la nouvelle valeur de la variable


denvironnement LOGNAME avant de se terminer.

Ex : $ echo $LOGNAME
sanchis => valeur initiale de la variable denvironnement
$
$ LOGNAME=$(modifLOGNAME) => capture de la nouvelle valeur
$
$ echo $LOGNAME
Eric => la variable denvironnement a t modifie
$

Excute par un processus fils, la modification apporte par modifLOGNAME sur son propre
environnement est transmise au processus pre (linterprteur bash) via :
- laffichage de la nouvelle valeur (ct fils)
- la substitution de commande (ct pre).
2
Une entre est dite visible si son nom ne commence pas par un point.

35
2. Substitutions de commandes et paramtres rgionaux
Cr par des informaticiens amricains, le systme Unix tait originellement destin des
utilisateurs anglophones. La diffusion des systmes de la famille Unix (dont GNU/Linux) vers des
publics de langues et de cultures diffrentes a conduit leurs dveloppeurs introduire des
paramtres rgionaux (locale). Ces derniers permettent par exemple de fixer la langue d'affichage
des messages, le format des dates ou des nombres. Les paramtres rgionaux se prsentent
l'utilisateur sous la forme de variables prdfinies dont le nom commence par LC_.

La commande unix locale utilise sans argument affiche la valeur courante de ces informations
rgionales.

Ex : $ locale
LANG=fr_FR.UTF-8
LANGUAGE=
LC_CTYPE="fr_FR.UTF-8"
LC_NUMERIC="fr_FR.UTF-8"
LC_TIME="fr_FR.UTF-8"
LC_COLLATE="fr_FR.UTF-8"
LC_MONETARY="fr_FR.UTF-8"
LC_MESSAGES="fr_FR.UTF-8"
LC_PAPER="fr_FR.UTF-8"
LC_NAME="fr_FR.UTF-8"
LC_ADDRESS="fr_FR.UTF-8"
LC_TELEPHONE="fr_FR.UTF-8"
LC_MEASUREMENT="fr_FR.UTF-8"
LC_IDENTIFICATION="fr_FR.UTF-8"
LC_ALL=
$

Des commandes telles que date utilisent ces valeurs pour afficher leurs rsultats.

Ex : $ date
lundi 24 mars 2014, 16:28:02 (UTC+0100)
$

On remarque que le format du rsultat correspond bien une date la franaise (jour de la
semaine, jour du mois, mois, anne). Si cette internationalisation procure un confort indniable
lors d'une utilisation interactive du systme, elle pose problme lorsque l'on doit crire un
programme shell se basant sur la sortie d'une telle commande, sortie qui dpend troitement de la
valeur des paramtres rgionaux. La portabilit du programme shell en est fortement fragilise.

Toutefois, le fonctionnement standard dun systme Unix traditionnel peut tre obtenu en
choisissant la locale standard appele C. Pour que cette locale naffecte temporairement que
les rsultats dune seule commande, par exemple date, il suffit dexcuter la commande
LC_ALL=C date

Ex : $ LC_ALL=C date
Mon Mar 24 16:29:10 CET 2014
$

On saperoit quavec la locale standard, le jour du mois est en troisime position alors quavec la
locale prcdente, il tait en deuxime position. Pour obtenir de manire portable le jour courant
du mois, on pourra excuter les commandes suivantes :

36
Ex : $ set $(LC_ALL=C date) ; echo $3
24
$

37
Chapitre 4 : Caractres et expressions
gnriques

Les caractres et expressions gnriques sont issus d'un mcanisme plus gnral appel
expressions rationnelles (regular expressions) ou expressions rgulires. Ces caractres et
expressions sont utiliss pour spcifier un modle de noms d'entres. Ce modle est ensuite
interprt par le shell pour crer une liste trie de noms d'entres. Par dfaut, le shell traite
uniquement les entres non caches du rpertoire courant ; cela signifie que les entres dont le
nom commence par le caractre . sont ignores.

Pour illustrer lutilisation des caractres et expressions gnriques, on utilisera un rpertoire


appel generique contenant les 16 entres suivantes :

$ pwd
/home/sanchis/generique
$
$ ls -l
total 0
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 1
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 a
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 _a
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 A
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 ami
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 an
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59 Arbre
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59 e
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59 mirat
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59 En
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59 tat
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59 minuit
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59 zaza
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59 Zoulou
$

La valeur des paramtres rgionaux influe grandement sur linterprtation et la mthode de tri
des noms dentres. Si on utilise la locale standard, on obtient laffichage suivant :
$ LC_ALL=C ls -l
total 0
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:58 1
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:58 A
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:59 Arbre
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:59 En
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:59 Zoulou
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:58 _a
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:58 a
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:58 ami
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:58 an
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:59 e
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:59 minuit
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:59 zaza
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:58 ??
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:59 ??
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:59 ??mirat
-rw-rw-r-- 1 sanchis sanchis 0 Mar 27 15:59 ??tat
$

38
On saperoit que linterprtation des noms dentres contenant des caractres accentus est
altre.

1. Caractres gnriques
Les caractres gnriques du shell sont : * ? []

Remarque : il ne faut pas confondre la syntaxe [] du mta-langage [cf. Chapitre 1, 2] et


les caractres gnriques [] du shell.

Pour que bash interprte les caractres gnriques, il est ncessaire que l'option noglob de la
commande interne set soit l'tat off. Pour connatre l'tat des diffrentes options de la
commande interne set, on utilise la commande set o.

Ex : $ set o
allexport off
braceexpand on
emacs on
errexit off
errtrace off
functrace off
hashall on
histexpand on
history on
ignoreeof off
interactive-comments on
keyword off
monitor on
noclobber off
noexec off
noglob off
nolog off
notify off
nounset off
onecmd off
physical off
pipefail off
posix off
privileged off
verbose off
vi off
xtrace off
$

1.1 Le caractre *

Le caractre gnrique * dsigne n'importe quelle suite de caractres, mme la chane vide.

Ex : $ echo *
1 a _a A ami an Arbre e mirat En tat minuit zaza Zoulou
$

Tous les noms d'entres sont affichs, tris.

Ex : $ ls -l a*

39
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 a
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 ami
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 an
$

La notation a* dsigne toutes les entres du rpertoire courant dont le nom commence par la
lettre a. Par consquent, dans la commande ls l a* le shell remplace la chane a* par la
chane : a ami an
En dautres termes, la commande unix ls ne voit pas le caractre * puisquil est prtrait
par le shell.

$ echo *a* => noms des entres contenant un caractre a


a _a ami an mirat tat zaza
$

Remarques :

- quand aucune entre ne correspond au modle fourni, les caractres et expressions


gnriques ne sont pas interprts (cf. option nullglob la fin de ce chapitre).

Ex : $ echo Z*t
Z*t
$

- le caractre . qui dbute le nom des fichiers cachs (ex: .profile) ou de rpertoires
(ex : ..) ainsi que le caractre / doivent tre explicitement mentionns dans les
modles (cf. option dotglob la fin de ce chapitre).

Ex : $ pwd
/home/sanchis
$ echo .pr* ../../bi*
.profile ../../bin
$

1.2 Le caractre ?

Le caractre gnrique ? dsigne un et un seul caractre.

Ex : $ echo ? => noms dentres composs dun seul caractre


1 a A e
$
$ echo ?n
an En
$

Plusieurs caractres gnriques diffrents peuvent tre prsents dans un modle.

Ex : $ echo ?mi*
ami mirat
$

Exercice 1 : Ecrire un modle permettant d'afficher le nom des entres dont le deuxime
caractre est un a.

40
Exercice 2 : Ecrire un modle permettant d'afficher le nom des entres dont le premier
caractre est un a suivi par deux caractres quelconques.

1.3 Les caractres []

Les caractres gnriques [] dsignent un seul caractre parmi un groupe de caractres.

Ce groupe est prcis entre les caractres []. Il peut prendre deux formes : la forme ensemble
et la forme intervalle.

Forme ensemble : tous les caractres souhaits sont explicitement mentionns entre [].

Ex : $ ls -l [ame]
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:58 a
-rw-rw-r-- 1 sanchis sanchis 0 mars 27 15:59 e
$
$ echo ?[ame]*
_a ami mirat zaza
$

Le modle [ame] dsigne tous les noms d'entres constitus d'un seul caractre a, m ou e.

Forme intervalle : seules les bornes de l'intervalle sont prcises et spares par un - .

Ex : $ echo *
1 a _a A ami an Arbre e mirat En tat minuit zaza Zoulou
$
$ echo [a-z]* => le caractre Z est ignor
a A ami an Arbre e mirat En tat minuit zaza
$
$ echo [A-Z]* => le caractre a est ignor
A Arbre e mirat En tat minuit zaza Zoulou
$

Linterprtation du modle [a-z] est conditionne par la valeur des paramtres rgionaux :
cette syntaxe est donc non portable et il est dconseill de lemployer car elle peut avoir des
effets nfastes lorsquelle est utilise avec la commande unix rm.

Si l'on souhaite dsigner une classe de caractres tels que les minuscules ou les majuscules, il
est prfrable d'utiliser la syntaxe POSIX 1003.2 correspondante. Ce standard dfinit des
classes de caractres sous la forme [:nom_classe:]

Des exemples de classes de caractres dfinies dans ce standard sont :


[:upper:] (majuscules)
[:lower:] (minuscules)
[:digit:] (chiffres, 0 9)
[:alnum:] (caractres alphanumriques).

Attention : pour dsigner n'importe quel caractre d'une classe, par exemple les
minuscules, on place la classe entre les caractres gnriques [].

41
Ex : $ echo [[:lower:]] => noms d'entres constitus d'une seule minuscule
a e
$

Si lon omet de placer le nom de la classe entre les caractres gnriques [], ce sont les
caractres [] du nom de la classe qui seront interprts par le shell comme caractres
gnriques.

Ex : $ echo [:lower:] => sera interprt comme [:lower:]


e
$

Pour afficher les noms d'entres commenant par une majuscule :

Ex : $ echo [[:upper:]]*
A Arbre En Zoulou
$

Pour afficher les noms d'entres commenant par une majuscule ou le caractre a :

Ex : $ echo [[:upper:]a]*
a A ami an Arbre En Zoulou
$

Il est possible de mentionner un caractre ne devant pas figurer dans un groupe de caractres.
Il suffit de placer le caractre ! juste aprs le caractre [.

Ex : $ echo ?[!n]* => noms d'entres ne comportant pas le caractre n en 2me position
_a ami Arbre mirat tat minuit zaza Zoulou
$
$ echo [![:lower:]]
1 A
$
$ echo [![:upper:]]*
1 a _a ami an e mirat tat minuit zaza
$
$ echo [![:upper:]]*[!at]
ami an
$

2. Expressions gnriques
Pour que bash interprte les expressions gnriques, il est ncessaire que loption extglob de
la commande interne shopt soit active.

Ex : $ shopt
autocd off
cdable_vars off
cdspell off
checkhash off
checkjobs off
checkwinsize on
cmdhist on
compat31 off
compat32 off

42
compat40 off
compat41 off
dirspell off
dotglob off
execfail off
expand_aliases on
extdebug off
extglob on
extquote on
failglob off
force_fignore on
globstar off
gnu_errfmt off
histappend on
histreedit off
histverify off
hostcomplete off
huponexit off
interactive_comments on
lastpipe off
lithist off
login_shell off
mailwarn off
no_empty_cmd_completion off
nocaseglob off
nocasematch off
nullglob off
progcomp on
promptvars on
restricted_shell off
shift_verbose off
sourcepath on
xpg_echo off
$

Pour activer une option de la commande interne shopt on utilise la commande : shopt s opt
Pour activer le traitement des expressions gnriques par le shell : shopt s extglob

Les expressions gnriques de bash sont :

?(liste_modles) : correspond 0 ou 1 occurrence de chaque modle

*(liste_modles) : correspond 0,1 ou plusieurs occurrences de chaque modle

+(liste_modles) : correspond au moins 1 occurrence de chaque modle

@(liste_modles) : correspond exactement 1 occurrence de chaque modle

!(liste_modles) : correspond tout sauf aux modles mentionns

Dans une expression gnrique, liste_modles dsigne une suite dun ou plusieurs modles
spars par un caractre |. Dans ce contexte, le caractre | signifie OU.

Ex : $ echo +([[:lower:]]) => noms constitus que de minuscules


a ami an e mirat tat minuit zaza
$
$ echo !(+([[:lower:]]))
1 _a A Arbre En Zoulou
$
$ echo !(*at|a*)

43
1 _a A Arbre e En minuit zaza Zoulou
$

Exercice 3 : Ecrire un modle correspondant aux noms d'entres comportant plus de deux
caractres.

Si lon souhaite utiliser les expressions gnriques dans un fichier shell, on y inclura
pralablement la commande shopt s extglob.

3. Options relatives aux caractres et expressions gnriques


(1) Pour grer ses propres options, bash intgre deux commandes : set et shopt.

Dun point de vue pratique,


- pour connatre l'tat des options de la commande interne set : set o
- pour activer une option de la commande interne set : set o option
- pour dsactiver une option de la commande interne set : set +o option
- pour connatre l'tat des options de la commande interne shopt : shopt
- pour activer une option de la commande interne shopt : shopt -s option
- pour dsactiver une option de la commande interne shopt : shopt -u option

(2) Outre extglob, dautres options de la commande interne shopt permettent de modifier la
cration de la liste des noms dentres. Ces options sont : dotglob, nocaseglob, nullglob,
failglob. Par dfaut, elles sont inactives (off).

A ltat on :
dotglob signifie que les noms dentres commenant par . (caractre point) seront
galement traits
nocaseglob signifie que les majuscules et minuscules ne seront pas diffrencies
nullglob signifie quun modle ne correspondant aucune entre sera remplac par
une chane vide et non par le modle lui-mme
failglob signifie quun modle ne correspondant aucune entre provoquera une
erreur.

Ex : $ pwd
/home/sanchis/glob
$
$ ls -la
total 8
drwxr-xr-x 2 sanchis sanchis 4096 nov. 24 2011 .
drwxr-xr-x 5 sanchis sanchis 4096 nov. 27 2012 ..
-rw-r--r-- 1 sanchis sanchis 0 nov. 24 2011 .sessions
-rw-r--r-- 1 sanchis sanchis 0 nov. 24 2011 video
-rw-r--r-- 1 sanchis sanchis 0 nov. 24 2011 viDEos
$
$ echo p*
p* => comportement par dfaut
$
$ shopt -s nullglob
$

44
$ echo p*
=> chane vide
$
$ shopt -s failglob
$
$ echo p*
bash: Pas de correspondance : p* => message derreur
$
$ echo *s*
viDEos => comportement par dfaut
$
$ shopt -s dotglob
$
$ echo *s*
.session viDEos => fichier cach .session pris en compte
$
$ echo *d*
Video => comportement par dfaut
$
$ shopt -s nocaseglob
$
$ echo *d*
video viDEos
$

(3) A ltat on, loption noglob de la commande interne set supprime linterprtation des
caractres et expressions gnriques.

Ex : $ ls -la
total 8
drwxr-xr-x 2 sanchis sanchis 4096 mars 27 20:21 .
drwxr-xr-x 7 sanchis sanchis 4096 mai 4 16:37 ..
-rw-r--r-- 1 sanchis sanchis 0 nov. 24 2011 .sessions
-rw-r--r-- 1 sanchis sanchis 0 nov. 24 2011 video
-rw-r--r-- 1 sanchis sanchis 0 nov. 24 2011 viDEos
$
$ shopt -u dotglob => le fichier cach .session ne sera pas pris en compte
$ shopt -s extglob => interprtation des expressions gnriques active
$ set +o noglob => interprtation des caractres gnriques active
$
$ echo +([[:lower:]]) *
video video videos
$
$ set o noglob => suppression de linterprtation
$ set -o | grep noglob
noglob on
$
$ echo +([[:lower:]]) *
+([[:lower:]]) * => aucune interprtation
$

45
Chapitre 5 : Redirections lmentaires

1. Descripteurs de fichiers

Un processus Unix possde par dfaut trois voies dinteraction avec lextrieur appeles entres /
sorties standard identifies par un entier positif ou nul appel descripteur de fichier.
Ces entres / sorties standard sont :
- une entre standard, de descripteur 0
- une sortie standard, de descripteur 1
- une sortie standard pour les messages derreurs, de descripteur 2.

Toute commande tant excute par un processus, nous dirons galement quune commande
possde trois entres / sorties standard.

0 1
commande
2

De manire gnrale, une commande de type filtre (ex : cat) prend ses donnes sur son entre
standard qui correspond par dfaut au clavier, affiche ses rsultats sur sa sortie standard, par
dfaut lcran, et affiche les erreurs ventuelles sur sa sortie standard pour les messages derreurs,
par dfaut lcran galement.

2. Redirections lmentaires

On peut rediriger sparment chacune des trois entres/sorties standard dune commande. Cela
signifie quune commande pourra :
- lire les donnes traiter partir dun fichier et non du clavier de lutilisateur
- crire les rsultats ou erreurs dans un fichier et non lcran.

2.1 Redirection de la sortie standard

Syntaxe : > fichier ou 1> fichier

Ex : $ pwd
/home/sanchis
$ pwd > fich
$ => aucun rsultat affich lcran !
$ cat fich => le rsultat a t enregistr dans le fichier fich
/home/sanchis
$

Cette premire forme de redirection de la sortie standard crase l'ancien contenu du fichier de
sortie (fichier fich) si celui-ci existait dj, sinon le fichier est cr.

46
Le shell prtraite une commande avant de lexcuter : dans lexemple ci-dessous, le shell cre un
fichier vide f devant recevoir les rsultats de la commande (ici inexistante) ; lunique effet de >f
sera donc la cration du fichier f ou sa remise zro.

Ex : $ >f => cre ou remet zro le fichier f


$
$ ls -l f
-rw-rw-r-- 1 sanchis sanchis 0 mars 31 10:26 f
$

Une commande ne possde quune seule sortie standard ; par consquent, si on dsire effacer le
contenu de plusieurs fichiers, il est ncessaire dutiliser autant de commandes que de fichiers
effacer. Le caractre ; permet dexcuter squentiellement plusieurs commandes crites sur la
mme ligne.

Ex : $ > f1 ; >f2
$

La redirection de la sortie standard de la commande unix cat est souvent utilise pour affecter un
contenu succinct un fichier.

Ex : $ cat >tata => lentre standard est directement recopie dans tata
a demain
si vous le voulez bien
^D
$
$ cat tata
a demain
si vous le voulez bien
$

a demain 0 1
cat
si vous le voulez bien

tata

Pour concatner (cest dire ajouter la fin) la sortie standard d'une commande au contenu d'un
fichier, une nouvelle forme de redirection doit tre utilise : >> fichier

Ex : $ pwd > t
$
$ date >> t
$
$ cat t
/home/sanchis
lundi 31 mars 2014, 10:28:24 (UTC+0200)
$

Comme pour la redirection prcdente, lexcution de >> fich cre le fichier fich sil nexistait
pas.

47
2.2 Redirection de la sortie standard pour les messages d'erreur

Syntaxe : 2> fichier

On ne doit laisser aucun caractre espace entre le chiffre 2 et le symbole >.

Ex : $ pwd
/home/sanchis
$ ls vi => lditeur de texte vi se trouve dans le rpertoire /usr/bin
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
$
$ ls vi 2> /dev/null
$

Le fichier spcial /dev/null est appel poubelle ou puits car toute sortie qui y est redirige,
est perdue. En gnral, il est utilis lorsquon est davantage intress par le code de retour [cf.
Chapitre 7] de la commande plutt que par les rsultats ou messages derreur quelle engendre.

Pour crire un message mess sur la sortie standard pour les messages derreur :
echo >&2 mess

Comme pour la sortie standard, il est possible de concatner la sortie standard pour les messages
derreur d'une commande au contenu d'un fichier : 2>> fichier

Ex : $ ls vi
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
$
$ ls vi 2>err
$
$ ls date 2>>err
$
$ cat err
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
ls: impossible d'accder date: Aucun fichier ou dossier de ce type
$

Pour rediriger la sortie standard pour les messages derreur vers la sortie standard (c.--d. vers le
fichier de descripteur 1), on utilisera la syntaxe : 2>&1
Cela est souvent utilis lorsquon dsire conserver dans un mme fichier toutes les sorties.

Ex : $ ls vi err >trace 2>&1


$
$ cat trace
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
err
$

La sortie standard est redirige vers le fichier trace [a] puis la sortie standard pour les messages
derreur est redirige vers la sortie standard, c.--d. galement vers le fichier trace [b].

48
1
ls vi err Ecran

trace

[a]

1
ls vi err Ecran

trace

[b]

La syntaxe &> fichier est quivalente la syntaxe > fichier 2>&1

Ex : $ ls vi err &> trace


$
$ cat trace
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
err
$

Lajout en fin de fichier seffectue en utilisant la syntaxe &>> fichier

Ex : $ ls /etc/passwd date &>> trace


$
$ cat trace
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
err
ls: impossible d'accder date: Aucun fichier ou dossier de ce type
/etc/passwd
$

Attention : Les redirections tant traites de gauche droite, lordre des redirections est
important.

Exercice 1 : Que fait la commande : ls vi err 2>&1 >trace

Pour viter que le contenu dun fichier ne soit cras lors dune redirection malheureuse, il est
possible dutiliser loption noclobber de la commande interne set.

Ex : $ cat t
bonjour
$
$ set -o noclobber => activation de loption noclobber
$
$ echo coucou > t
bash: t : impossible d'craser le fichier existant

49
$
$ ls vi 2>t
bash: t : impossible d'craser le fichier existant
$
$ echo ciao >> t
$ => la concatnation reste possible
$ cat t
bonjour
ciao
$
$ set +o noclobber => pour dsactiver loption
$

2.3 Redirection de l'entre standard

Syntaxe : < fichier

Ex : $ mail sanchis < lettre


$

La commande unix mail envoie lutilisateur sanchis le contenu du fichier lettre.

Une substitution de commande associe une redirection de lentre standard permet daffecter
une variable le contenu dun fichier. En effet, la substitution de commande $(cat fichier) peut tre
avantageusement remplace par la syntaxe $(< fichier). Cette deuxime forme est plus rapide.

Ex : $ cat fic_noms
pierre beteille
anne debazac
julie donet
$
$ liste=$(<fic_noms)
$
$ echo $liste => liste est une variable et non un fichier !
pierre beteille anne debazac julie donet => elle contient le contenu du
$ => fichier fic_noms

La plupart des commandes affichent leurs rsultats sous la mme forme, suivant que lon passe en
argument le nom dun fichier ou que lon redirige son entre standard avec ce fichier.

Ex : $ cat fic => cat ouvre le fichier fic afin de lire son contenu
bonjour
et au revoir
$
$ cat <fic => cat lit son entre standard (redirige par le shell), sans savoir
bonjour => quil sagit du contenu du fichier fic
et au revoir
$

Il nen est pas ainsi avec la commande unix wc : celle-ci ncrit pas les rsultats de la mme
manire suivant quun argument lui a t fourni ou bien quelle lise son entre standard.

Ex : $ wc -l fic_noms
3 fic_noms
$

50
$ wc -l < fic_noms
3
$

Par consquent, lorsque lon dsirera traiter la sortie dune commande unix wc, il faudra prendre
garde la forme utilise. La deuxime forme est prfrable lorsquon ne souhaite obtenir que le
nombre de lignes.

Ex : $ nblignes=$( wc -l < fic_noms )


$
$ echo $nblignes
3 => nombre de lignes
$

Exercice 2 : Ecrire un programme shell nblignes prenant un nom de fichier en argument et qui
affiche le nombre de lignes de ce fichier.

Ex : $ nblignes fich_noms
3
$

2.4 Redirections spares des entres / sorties standard

Les entres / sorties peuvent tre rediriges indpendamment les unes des autres.

Ex : $ wc -l <fic_noms >fic_nblignes 2>err


$
$ cat fic_nblignes
3
$
$ cat err
$

La commande wc -l affiche le nombre de lignes dun ou plusieurs fichiers texte. Ici, il sagit du
nombre de lignes du fichier fic_noms. Le fichier err est cr mais est vide car aucune erreur ne
sest produite. Dans cet exemple, la disposition des redirections dans la ligne de commande na
pas dimportance, car les deux sorties ne sont pas rediriges vers le mme fichier.

Il est possible de placer les redirections o l'on souhaite car le shell traite les redirections avant
d'excuter la commande.

Ex : $ < fic_noms > fic_nblignes wc 2>err -l


$
$ cat fic_nblignes
3
$
$ cat err
$

2.5 Texte joint

Il existe plusieurs syntaxes lgrement diffrentes pour passer un texte comme entre une
commande. La syntaxe prsente ci-dessous est la plus simple :

51
cmd <<mot
texte
mot

Lutilisation de cette syntaxe permet dalimenter lentre standard de la commande cmd laide
dun contenu texte comprenant ventuellement plusieurs lignes et dlimit par deux balises mot.
La deuxime balise mot doit imprativement se trouver en dbut de ligne. Par contre, un ou
plusieurs caractres espace ou tabulation peuvent tre prsents entre << et mot.

Ex : $ a=3.5 b=1.2
$
$ bc << EOF
> $a + $b => la chane "> " indique que la commande nest syntaxiquement
> EOF => pas termine
4.7
$

La commande unix bc est une calculatrice utilisable en ligne de commande. Dans lexemple ci-
dessus, deux variables a et b sont initialises respectivement avec les chanes de caractres 3.5 et
1.2. Le shell effectue les deux substitutions de variables prsentes entre les mots EOF puis
alimente lentre standard de bc avec le texte obtenu. Cette commande calcule la valeur de
lexpression puis affiche son rsultat sur sa sortie standard.

Lorsque bash dtecte quune commande nest pas syntaxiquement termine, il affiche une chane
dappel diffrente (contenue dans la variable prdfinie PS2 du shell) matrialise par un caractre
> suivi dun caractre espace, invitant lutilisateur continuer la saisie de sa commande.

2.6 Chane jointe

Syntaxe : cmd <<< chane

Cest une syntaxe plus compacte que le texte joint : le contenu transmis lentre standard de la
commande cmd se prsente sous la forme dune chane de caractres chane.

Ex : $ a=1.2 b=-5.3
$
$ bc <<< "$a + $b"
-4.1
$

Le choix dutiliser un texte joint ou bien une chane jointe seffectue suivant la structure et la
longueur du texte transmettre la commande cmd.

Exercice 2 : Ecrire un programme shell add prenant deux nombres en arguments et qui affiche
leur somme.

Ex : $ add 1.2 -6
-4.8
$

52
2.7 Fermeture des entres / sorties standard

Fermeture de lentre standard : <&-


Fermeture de la sortie standard : >&-
Fermeture de la sortie standard pour les messages derreur : 2>&-

Ex : $ >&- echo coucou


bash: echo: erreur d'criture : Mauvais descripteur de fichier
$

Il y a fermeture de la sortie standard puis une tentative dcriture sur celle-ci : lerreur est signale
par linterprteur de commandes.

3. Tubes

Le mcanisme de tube (symbolis par le caractre |) permet denchaner lexcution de


commandes successives en connectant la sortie standard dune commande lentre standard de la
commande suivante :

Ex : ls -l /bin | more

Il y a affichage du contenu du rpertoire /bin (commande ls -l /bin) cran par cran (commande
unix more). En effet, les informations affiches par ls -l sont envoyes vers lentre de la
commande unix more qui les affiche cran par cran. La sortie standard de la dernire commande
ntant pas redirige, laffichage final seffectue lcran.

1 0 1
ls -l /bin | more

2 2

Un rsultat quivalent aurait pu tre obtenu dune manire moins lgante en excutant la suite de
commandes :
ls -l /bin >temporaire ; more < temporaire ; rm temporaire

La commande ls -l /bin crit le rsultat dans le fichier temporaire ; ensuite, on affiche cran par
cran le contenu de ce fichier ; enfin, on efface ce fichier devenu inutile. Le mcanisme de tube
vite lutilisateur de grer ce fichier intermdiaire.

3.1 Pipelines

De manire simplifie, on appelle pipeline, une suite non vide de commandes connectes par des
tubes : cmd1 | ... | cmdn

Chaque commande est excute par un processus distinct, la sortie standard de la commande
cmdi-1 tant connecte lentre standard de la commande cmdi.

53
Ex : $ date | tee trace1 trace2 | wc -l
1 => date ncrit ses rsultats que sur une seule ligne
$
$ cat trace1
lundi 31 mars 2014, 10:31:56 (UTC+0200)
$
$ cat trace2
lundi 31 mars 2014, 10:31:56 (UTC+0200)
$

La commande unix tee crit le contenu de son entre standard sur sa sortie standard tout en
gardant une copie dans le ou les fichiers dont on a pass le nom en argument.
Dans lexemple ci-dessus, tee crit le rsultat de date dans les fichiers trace1 et trace2 ainsi que
sur sa sortie standard, rsultat pass la commande wc -l.

3.2 Tubes et chanes jointes

Le shell cre un processus diffrent pour chaque commande dun tube cmd1 | cmd2. Cela
provoque leffet suivant : si cmd2 modifie la valeur dune variable, cette modification disparaitra
avec la fin du processus qui excute cette commande.

Ex : $ a=bonjour
$ echo $a | read rep # (a)
$ echo $rep
=> la variable rep ne contient pas la chane bonjour ; elle nest pas initialise
$

Si lon fait afficher la valeur de la variable rep, ligne (a), par le mme processus qui a lu la valeur,
alors on saperoit que laffectation a bien t effectue mais celle-ci disparait avec la fin de ce
processus.
Pour voir ce comportement, on place les deux commandes lintrieur dune paire de
parenthses (cf. Chapitre 6).

Ex : $ echo $a | ( read rep ; echo $rep )


bonjour => cet affichage montre que laffectation rep a bien t effectue
$
$ echo $rep
=> variable rep non initialise
$

Cela provient du fait quil y a deux variables rep diffrentes : une qui est cre et utilise par le
processus qui excute la commande read rep et une qui est cre et utilise par le processus qui
excute la commande echo $rep.

Lutilisation dune chane jointe permet de rsoudre de manire lgante ce problme de


transmission de donnes entre processus.

Ex : $ read rep <<< "$a"


$
$ echo $rep
bonjour
$

54
4. Substitution de processus

La substitution de processus gnralise la notion de tube. La principale forme de substitution de


processus est la suivante : cmd <(suite_cmds)

Le shell cre un fichier temporaire, connecte la sortie de suite_cmds ce fichier temporaire puis
lance lexcution de cette suite de commandes. Cette suite de commandes crit ses rsultats dans
le fichier temporaire. Ensuite, le shell remplace la syntaxe <(suite_cmds) par la rfrence ce
fichier temporaire et lance lexcution de la commande cmd.
Du point de vue de cette commande cmd, tout se passe comme si les donnes produites par
suite_cmds taient prsentes dans un fichier ordinaire dont lutilisateur lui aurait pass le nom en
argument.

Ex : $ ls -l
total 8
-rw-rw-r-- 1 sanchis sanchis 140 mars 31 10:29 err
-rw-rw-r-- 1 sanchis sanchis 0 mars 31 10:26 f
-rw-r--r-- 1 sanchis sanchis 156 mars 31 10:30 trace
$
$ wc -l <(ls -l)
4 /dev/fd/63 => la commande ls l affiche 4 lignes
$

Dans lexemple ci-dessus, la sortie de la commande ls l a t enregistre dans un fichier


temporaire /dev/fd/63. Puis, la commande wc l /dev/fd/63 a t excute.

La substitution de processus est intressante car elle permet de crer en parallle plusieurs flots de
donnes qui seront ensuite traits squentiellement par la mme commande.

La syntaxe de la commande se prsente alors sous la forme :


cmd <(suite_cmds1) <(suite_cmds2)
Lexcution des suites de commandes suite_cmdsi est effectue en parallle, chaque flot de
rsultats produit par celles-ci tant enregistr dans un fichier temporaire diffrent. Puis, le shell
substitue chaque syntaxe <(suite_cmdsi) par la rfrence au fichier temporaire correspondant.
Enfin, la commande cmd est excute munie de ces diffrents arguments.

Lexemple ci-dessous illustre le cas o lon souhaite afficher la premire ligne de deux fichiers
fich1 et fich2 non tris et pouvant contenir des doublons.

Ex : $ cat fich1
Pierre
Anne
Pierre
Pierre
Jean
$
$ cat fich2
Paul
Paul
Pierre
Jean
$
$ head -q -n 1 <(sort fich1 | uniq) <(sort fich2 | uniq)
Anne
Jean
$

55
Dans un premier temps, les fichiers fich1 et fich2 sont tris (commande unix sort) en parallle et
dbarrasss de leurs doublons (commande unix uniq). Le rsultat du traitement de ces deux
fichiers est plac dans deux fichiers temporaires pralablement crs par bash (les contenus de
fich1 et fich2 restent, eux, inchangs). Puis, la premire ligne (option n 1 de la commande unix
head) de chacun de ces deux fichiers est affiche, sans mentionner les noms de fichiers (option
-q).

En rsum, la substitution de processus <(suite_cmds) peut tre utilise dans une commande cmd
en lieu et place dun nom de fichier dont le contenu sera lu par cette commande.

56
Chapitre 6 : Groupement de commandes

Le shell fournit deux mcanismes pour grouper lexcution dun ensemble de commandes
sans pour cela affecter un nom ce groupement :
- linsertion de la suite de commandes entre une paire daccolades
- linsertion de cette suite de commandes entre une paire de parenthses.

{ suite_cmds ; }

Insre entre une paire daccolades, la suite de commandes est excute dans le shell courant.
Cela a pour effet de prserver les modifications apportes par la suite de commandes sur
lenvironnement du processus courant.

Ex : $ pwd
/home/sanchis => rpertoire initial
$
$ { cd /bin ; pwd ; } => changement du rpertoire courant
/bin
$
$ pwd
/bin => rpertoire final (le changement a t prserv !)
$

Sexcutant dans le shell courant, les modifications apportes aux variables sont galement
conserves :

Ex : $ a=bonjour
$
$ { a=coucou ; echo $a ;}
coucou
$
$ echo $a
coucou
$

Les accolades { et } sont deux mots-cl de bash ; chacune delles doit donc tre le premier
mot dune commande. Pour cela, chaque accolade doit tre le premier mot de la ligne de
commande ou bien tre prcde dun caractre ;. De plus, suite_cmds ne doit pas coller
laccolade ouvrante {.
Par contre, la prsence ou absence dun caractre espace entre le caractre ; et le mot-cl } na
aucune importance.

Ex : $ { cd /bin } => laccolade } nest pas le premier mot dune commande


> => le shell ne dtecte pas la fin du groupement
> ^C => control-C
$
$ {cd /bin ;} => il manque un espace ou une tabulation entre { et cd
bash: Erreur de syntaxe prs du symbole inattendu }
$

57
Lance en arrire-plan, la suite de commandes nest plus excute par le shell courant mais
par un sous-shell.

Ex : $ pwd
/home/sanchis => rpertoire initial
$
$ { echo processus : ; cd / ; ps ;} &
processus :
[1] 27963
$ PID TTY TIME CMD
27942 pts/14 00:00:00 bash
27947 pts/14 00:00:00 bash
27963 pts/14 00:00:00 ps

[1] + Done { echo processus :; cd /; ps; }


$
$ pwd
/home/sanchis => rpertoire final
$

Bien quune commande cd / ait t excute, le rpertoire courant na pas t modifi


(/home/sanchis).

Une utilisation frquente du regroupement de commandes est la redirection globale de leur


entre ou sortie standard.

Ex : $ cat fich
premiere ligne
deuxieme ligne
troisieme ligne
quatrieme ligne
$
$ { read ligne1 ; read ligne2
> } < fich => le caractre > est affich par le shell, indiquant
$ => que laccolade } est manquante
$ echo $ligne1
premiere ligne
$ echo $ligne2
deuxieme ligne
$

Lentre standard des deux commandes read ligne1 et read ligne2 est globalement redirige :
elles liront squentiellement le contenu du fichier fich.

Si les commandes de lecture navaient pas t groupes, seule la premire ligne de fich aurait
t lue.

Ex : $ read ligne1 < fich ; read ligne2 < fich


$
$ echo $ligne1
premiere ligne
$
$ echo $ligne2
premiere ligne
$

58
Comme pour toutes commandes composes, lorsque plusieurs redirections de mme type sont
appliques la mme suite de commandes, seule la redirection la plus proche est effective.

Ex : $ { read lig1 ; read -p "Entrez votre ligne : " lig2 </dev/tty


> read lig3
> } < fich
Entrez votre ligne : bonjour tout le monde
$
$ echo $lig1
premiere ligne
$ echo $lig2
bonjour tout le monde
$ echo $lig3
deuxieme ligne
$

Les commandes read lig1 et read lig3 lisent le contenu du fichier fich mais la commande
read -p "Entrez votre ligne : " lig2 lit lentre standard originelle (/dev/tty).

(suite_cmds)

Insre entre une paire de parenthses, la suite de commandes est excute dans un sous-shell.
Lenvironnement du processus nest pas modifi aprs excution de la suite de commandes.
Les parenthses sont des oprateurs (et non des mots cl) : suite_cmds peut par consquent
coller une ou deux parenthses sans provoquer une erreur de syntaxe.

Ex : $ pwd
/home/sanchis => rpertoire initial
$
$ (cd /bin ; pwd)
/bin
$
$ pwd
/home/sanchis => le rpertoire initial na pas t modifi
$
$ b=bonjour
$
$ ( b=coucou ; echo $b )
coucou
$
$ echo $b
bonjour => la valeur de la variable b na pas t modifie
$

Ce type de groupement de commandes peut aussi tre utilis pour effectuer une redirection
globale.

Ex : $ ( pwd ; date ; echo FIN ) > fin


$
$ cat fin
/home/sanchis
lundi 31 mars 2014, 10:55:31 (UTC+0200)
FIN
$

59
1
Chapitre 7 : Code de retour

Un code de retour (exit status) est fourni par le shell aprs excution d'une commande.
Le code de retour est un entier positif ou nul, compris entre 0 et 255, indiquant si l'excution de la
commande s'est bien droule ou s'il y a eu un problme quelconque.
Par convention, un code de retour gal 0 signifie que la commande s'est excute correctement.
Un code diffrent de 0 signifie une erreur syntaxique ou d'excution.

Lvaluation du code de retour est essentielle lexcution de structures de contrle du shell telles
que if et while.

1. Paramtre spcial ?

Le paramtre spcial ? ( ne pas confondre avec le caractre gnrique ?) contient le code de


retour de la dernire commande excute de manire squentielle (excution synchrone).

Ex : $ pwd
/home/sanchis
$
$ echo $?
0 => la commande pwd s'est excute correctement
$ ls -l vi
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
$
$ echo $?
2 => une erreur sest produite !
$

Exercice 1 : En utilisant la commande unix ls et le mcanisme de redirection, crire un


programme shell dansbin prenant un nom de commande en argument et qui affiche
0 si cette commande est prsente dans /bin, une valeur diffrente de 0 sinon.

Ex : $ dansbin ls
0
$ dansbin who
2
$

Chaque commande positionne sa manire les codes de retour diffrents de 0. Ainsi, un code
de retour gal 1 positionn par la commande unix ls n'a pas la mme signification qu'un code de
retour gal 1 positionn par la commande unix grep. Les valeurs et significations du code de
retour dune commande unix ou du shell sont documentes dans les pages correspondantes du
manuel (ex : man grep).

Lorsque une commande est excute en arrire-plan (excution asynchrone), son code de retour
n'est pas mmoris dans le paramtre spcial ?.

1
Ce texte est paru sous une forme lgrement diffrente dans la revue Linux Magazine France , n39, mai
2002

60
Ex : $ pwd => mise zro du paramtre spcial ?
/home/sanchis
$
$ echo $?
0
$ ls -l vi & => commande excute en arrire-plan
[1] 5577
$ ls: impossible d'accder vi: Aucun fichier ou dossier de ce type

[1]+ Termine 2 ls --color=auto -l vi


$
$ echo $?
0
$

On remarque que la commande s'est termine avec la valeur 2 (Exit 2) mais que ce code de retour
n'a pas t enregistr dans le paramtre ?.

La commande interne deux-points (:) sans argument retourne toujours un code de retour gal 0.

Ex : $ : => commande deux-points


$ echo $?
0
$

Il en est de mme avec la commande interne echo : elle retourne toujours un code de retour gal
0, sauf cas particuliers.

Ex : $ 1>&- echo coucou


bash: echo: erreur d'criture : Mauvais descripteur de fichier
$
$ echo $?
1
$

Enfin, certaines commandes utilisent plusieurs valeurs pour indiquer des significations diffrentes,
comme la commande unix grep.

Commande unix grep :

Cette commande affiche sur sa sortie standard l'ensemble des lignes contenant une chane de
caractres spcifie en argument, lignes appartenant un ou plusieurs fichiers texte (ou par dfaut,
son entre standard).

La syntaxe de cette commande est : grep [ option(s) ] chane_cherche [ fich_texte1 ... ]

Soit le fichier pass contenant les cinq lignes suivantes :

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bertrand:x:101:100::/home/bertrand:/bin/bash
albert:x:102:100::/home/albert:/bin/bash
sanchis:x:103:100::/home/sanchis:/bin/bash

61
La commande ci-dessous affiche toutes les lignes du fichier pass contenant la chane sanchis.

Ex : $ grep sanchis pass


sanchis:x:103:100::/home/sanchis:/bin/bash
$

Attention : grep recherche une chane de caractres et non un mot.

Ex : $ grep bert pass


bertrand:x:101:100::/home/bertrand:/bin/bash
albert:x:102:100::/home/albert:/bin/bash
$

La commande affiche toutes les lignes contenant la chane bert (et non le mot bert).
Si lon souhaite la chane cherche en dbut de ligne, on utilisera la syntaxe
^chane_cherche. Si on la veut en fin de ligne : chane_cherche$

Ex : $ grep ^bert pass


bertrand:x:101:100::/home/bertrand:/bin/bash
$

La commande unix grep positionne un code de retour


- gal 0 pour indiquer qu'une ou plusieurs lignes ont t trouves
- gal 1 pour indiquer qu'aucune ligne n'a t trouve
- gal 2 pour indiquer la prsence d'une erreur de syntaxe ou qu'un fichier mentionn en
argument est inaccessible.

Ex : $ grep sanchis pass


sanchis:x:103:100::/home/sanchis:/bin/bash
$ echo $?
0
$
$ grep toto pass
$
$ echo $?
1 => la chane toto n'est pas prsente dans pass
$
$ grep sanchis tutu
grep: tutu: Aucun fichier ou dossier de ce type
$
$ echo $?
2 => le fichier tutu n'existe pas !
$

Exercice 2 : Ecrire un programme shell connu prenant en argument un nom dutilisateur qui
affiche 0 sil est enregistr dans le fichier pass, 1 sinon.

Ex : $ connu bert
1
$ connu albert
0
$

62
2. Code de retour d'un programme shell

Le code de retour d'un programme shell est le code de retour de la dernire commande qu'il a
excute.

Soit le programme shell lvi contenant l'unique commande ls vi.

#!/bin/bash
# @(#) lvi

ls vi

Cette commande produira une erreur car vi ne se trouve pas dans le rpertoire courant ; aprs
excution, le code de retour de lvi sera de celui de la commande ls vi (dernire commande
excute).

Ex : $ lvi
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
$
$ echo $?
2 => code de retour de la dernire commande excute par lvi
$ => c.--d. ls vi

Autre exemple avec le programme shell lvi1 de contenu :

#!/bin/bash
# @(#) lvi1

ls vi
echo Fin

La dernire commande excute par lvi1 sera la commande interne echo qui retourne un code de
retour gal 0.

Ex : $ lvi1
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
Fin
$
$ echo $?
0 => code de retour de la dernire commande excute par lvi (echo Fin)
$

Il est parfois ncessaire de positionner explicitement le code de retour d'un programme shell avant
qu'il ne se termine : on utilise alors la commande interne exit.

3. Commande interne exit

Syntaxe : exit [ n ]

Elle provoque l'arrt du programme shell avec un code de retour gal n.

63
Si n n'est pas prcis, le code de retour fourni est celui de la dernire commande excute.
Soit le programme shell lvi2 :

#!/bin/bash
# @(#) lvi2

ls vi
exit 23

Ex : $ lvi2
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
$
$ echo $?
23 => code de retour de exit 23
$

Le code de retour renvoy par ls vi est 2 ; en utilisant la commande interne exit, le programme
shell lvi2 positionne un code de retour diffrent (23).

4. Code de retour d'une suite de commandes

Le code de retour d'une suite de commandes est le code de retour de la dernire commande
excute.

Le code de retour de la suite de commandes cmd1 ; cmd2 ; cmd3 est le code de retour de la
commande cmd3.

Ex : $ pwd ; ls vi ; echo bonjour


/home/sanchis
ls: impossible d'accder vi: Aucun fichier ou dossier de ce type
bonjour
$ echo $?
0 => code de retour de echo bonjour
$

Il en est de mme pour le pipeline cmd1 | cmd2 | cmd3. Le code de retour sera celui de cmd3.

Ex : $ cat pass tutu | grep sanchis


cat: tutu: Aucun fichier ou dossier de ce type
sanchis:x:103:100::/home/sanchis:/bin/bash
$
$ echo $?
0 => code de retour de grep sanchis (le code de retour de cat pass tutu est 1)
$

Il est possible d'obtenir la ngation d'un code de retour d'un pipeline en plaant le mot-cl ! devant
celui-ci. Cela signifie que si le code de retour de pipeline est gal 0, alors le code de retour de !
pipeline est gal 1.

Ex : $ ! ls pass => le code de retour de ls pass est gal 0


pass

64
$
$ echo $?
1
$
$ ! cat pass | grep daemon
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
$
$ echo $?
1
$

Inversement, si le code de retour de pipeline est diffrent de 0, alors celui de ! pipeline est gal
0.

Ex : $ ! grep sanchis tutu


grep: tutu: Aucun fichier ou dossier de ce type
$
$ echo $?
0
$

5. Code de retour dune commande lance en arrire-plan

Il nexiste pas de mcanisme direct pour rcuprer le code de retour dune commande excute de
manire asynchrone. Une mthode permettant de lobtenir consiste utiliser le paramtre spcial !
( ne pas confondre avec le mot-cl ! prsent ci-dessus) et la commande interne wait.
Le paramtre spcial ! contient le numro didentification (pid) de la dernire commande
excute en arrire-plan.
La commande interne wait munie dun pid ou dun numro de job attend la fin du processus
correspondant et place le code de retour de ce dernier dans le paramtre spcial ?.

Ex : $ grep bert tutu & wait $! => (a)


[1] 6427
grep: tutu: Aucun fichier ou dossier de ce type
[1]+ Termine 2 grep --color=auto bert tutu
$
$ echo $? => (b)
2
$

Le shell lance la commande grep bert tutu en arrire-plan et attend qu'elle se termine (a), puis
affiche son code de retour (b).

6. Rsultats et code de retour

On ne doit pas confondre le rsultat d'une commande et son code de retour : le rsultat correspond
ce qui est crit sur sa sortie standard ; le code de retour indique uniquement si l'excution de la
commande s'est bien effectue ou non.

Parfois, on est intress uniquement par le code de retour d'une commande et non par les rsultats
qu'elle produit sur la sortie standard ou la sortie standard pour les messages d'erreurs.

65
Ex : $ grep toto pass > /dev/null 2>&1 => ou bien : grep toto pass &>/dev/null
$
$ echo $?
1 => on en dduit que la chane toto n'est pas prsente dans
$ => pass

7. Oprateurs && et || sur les codes de retour

Les oprateurs && et || autorisent lexcution conditionnelle dune commande cmd suivant la
valeur du code de retour de la dernire commande prcdemment excute.

Oprateur : &&

Syntaxe : cmd1 && cmd2

Le fonctionnement est le suivant : cmd1 est excute et si son code de retour est gal 0, alors
cmd2 est galement excute.

Ex : $ grep daemon pass && echo daemon existe


daemon:x:1:1:daemon:/usr/sbin:/bin/sh
daemon existe
$
La chane de caractres daemon est prsente dans le fichier pass, le code de retour renvoy par
lexcution de grep est 0 ; par consquent, la commande echo daemon existe est excute.

Oprateur : ||

Syntaxe : cmd1 || cmd2

cmd1 est excute et si son code de retour est diffrent de 0, alors cmd2 est galement excute.

Pour illustrer cela, supposons que le fichier tutu nexiste pas.

Ex : $ ls pass tutu
ls: impossible d'accder tutu: Aucun fichier ou dossier de ce type
pass
$
$ rm tutu || echo tutu non efface
rm: impossible de supprimer tutu: Aucun fichier ou dossier de ce type
tutu non efface
$

Le fichier tutu nexistant pas, la commande rm tutu affiche un message derreur et produit un code
de retour diffrent de 0 : la commande interne echo qui suit est donc excute.

66
Combinaisons doprateurs && et ||

Les deux rgles mentionnes ci-dessus sont appliques par le shell lorsqu'une suite de commandes
contient plusieurs oprateurs && et ||. Ces deux oprateurs ont mme priorit et leur valuation
seffectue de gauche droite.

Ex : $ ls pass || ls tutu || echo fini aussi


pass
$

Le code de retour de ls pass est gal 0 car pass existe, la commande ls tutu ne sera donc pas
excute. Dautre part, le code de retour de lensemble ls pass || ls tutu est le code de retour de
la dernire commande excute, cest dire est gal 0 (car cest le code de retour de ls pass),
donc echo fini aussi nest pas excute.

Intervertissons maintenant les deux commandes ls :

Ex : $ ls tutu || ls pass || echo fini


ls: impossible d'accder tutu: Aucun fichier ou dossier de ce type
pass
$

Le code de retour de ls tutu est diffrent de 0, donc ls pass sexcute. Cette commande renvoie un
code de retour gal 0, par consquent echo fini nest pas excute.

Combinons maintenant oprateurs && et || :

Ex : $ ls pass || ls tutu || echo suite et && echo fin


pass
fin
$

La commande ls pass est excute avec un code de retour gal 0, donc la commande ls tutu nest
pas excute : le code de retour de lensemble ls pass || ls tutu est gal 0, la commande echo
suite et nest pas excute. Le code de retour de ls pass || ls tutu || echo suite et est gal 0, donc
la commande echo fin est excute !

Bien sr, un raisonnement analogue sapplique avec loprateur && :

Ex : $ ls pass && ls tutu && echo fini


pass
ls: impossible d'accder tutu: Aucun fichier ou dossier de ce type
$
$ ls tutu && ls pass && echo suite et && echo fin
ls: impossible d'accder tutu: Aucun fichier ou dossier de ce type
$
$ ls pass && ls tutu && echo suite et || echo fin
pass
ls: impossible d'accder tutu: Aucun fichier ou dossier de ce type
fin
$

67
Exercice 3 :

a) Ecrire un programme shell present0 prenant en argument un nom dutilisateur et


affiche uniquement le code de retour 0 si lutilisateur est connect ou sinon affiche
1.

b) Modifier ce programme (soit present1) pour quil affiche le message "Connecte"


si lutilisateur est connect et naffiche rien sinon.

c) Modifier ce programme (soit present2) pour quil affiche le message "Connecte" si


cest le cas et affiche le message "Pas connecte" sinon.

d) Modifier ce programme (soit present) pour quil vrifie pralablement si le nom de


lutilisateur pass en argument existe dans le fichier /etc/passwd. Si ce nest pas le
cas, le programme ne doit rien afficher et se terminer avec le code de retour 1.
Sinon, il doit se comporter comme present2.

68
Chapitre 8 : Structures de contrle case et
while

1. Choix multiple case

Syntaxe : case mot in


[ modle [ | modle ] ... ) suite_de_commandes ;; ] ...
esac

Le shell value la valeur de mot puis compare squentiellement cette valeur chaque modle.
Ds qu'un modle correspond la valeur de mot, la suite de commandes associe est
excute, terminant l'excution de la commande interne compose case.

Les mots case et esac sont des mots-cl ; cela signifie que chacun deux doit tre le premier
mot dune commande.

suite_de_commandes doit se terminer par deux caractres point-virgule colls, de manire


ce quil ny ait pas dambigut avec lenchanement squentiel de commandes cmd1 ; cmd2.

Un modle peut tre construit laide des caractres et expressions gnriques de bash [cf.
Chapitre 4, Caractres et expressions gnriques].
Dans ce contexte, le symbole | signifie OU.
Pour indiquer le cas par dfaut, on utilise le modle *. Ce modle doit tre plac la fin de la
structure de contrle case.

Le code de retour de la commande compose case est gal 0 si aucun modle na pu


correspondre la valeur de mot. Sinon, cest celui de la dernire commande excute de
suite_de_commandes.

Exemple 1 : Programme shell oui affichant OUI si lutilisateur a saisi le caractre o ou O

#!/bin/bash
# @(#) oui

read p Entrez votre rponse : rep


case $rep in
o|O ) echo OUI ;;
*) echo Indefini
esac

Rq : - une substitution (de paramtre, de commande ou autre) doit tre prsente aprs
le mot-cl case (caractre $)

- il nest pas obligatoire de terminer la dernire suite_de_commandes par ;;

69
Exemple 2 : Programme shell nombre prenant une chane de caractres en argument et qui
affiche cette chane si elle est constitue dune suite de chiffres. Aucune
vrification nest effectue sur le nombre darguments passs au programme.

#!/bin/bash
# @(#) nombre

shopt -s extglob
case $1 in
+([[:digit:]]) ) echo $1 est une suite de chiffres ;;
esac

Rq : pour que les expressions gnriques puissent tre traites dans un fichier shell,
il est ncessaire dactiver loption correspondante (shopt -s extglob)

Exercice 1 : Ecrire un programme shell 4arg qui vrifie que le nombre d'arguments passs
lors de lappel du programme est gal 4 et crit suivant le cas le message
Correct ou le message Erreur.

Exercice 2 : Ecrire un programme shell reconnaitre qui demande lutilisateur dentrer un


mot, puis suivant le premire caractre de ce mot, indique sil commence par
un chiffre, une minuscule, une majuscule ou une autre sorte de caractre.

Exercice 3 : Tout systme Linux nest pas nativement configur pour afficher la date en
franais. En utilisant la commande unix date et la locale standard [cf. Chapitre
3, Substitution de commandes], crire un programme shell datefr qui affiche la
date courante en franais de la manire suivante :
mercredi 5 janvier 2005 10:00

Ignorer la casse :

Si lon souhaite ne pas distinguer majuscules et minuscules lors de la comparaison avec les
modles, il suffit de positionner loption nocasematch de la commande interne shopt.

Soit le fichier shell OUI :

#!/bin/bash
# @(#) OUI

read -p "Entrez un mot : " mot

shopt -s nocasematch
case $mot in
oui ) echo "Vous avez saisi le mot oui" ;;
* ) echo "$mot n'est pas le mot oui" ;;
esac

Ce programme shell reconnait le mot oui, crit avec des majuscules ou des minuscules.

Ex : $ OUI
Entrez un mot : Oui
Vous avez saisi le mot oui
$

70
$ OUI
Entrez un mot : aoui
aoui n'est pas le mot oui
$
$ OUI
Entrez un mot : oUI
Vous avez saisi le mot oui
$

Remarque : il ne faut pas confondre les options nocasematch et nocaseglob. L'option


nocasematch ne traite pas la casse lors de l'excution des commandes internes
case et [[ [cf. Chapitre 11, Entiers et expressions arithmtiques] tandis que
l'option nocaseglob ne traite pas la casse lors de la gnration des noms
d'entres [cf. Chapitre 4, Caractres et expressions gnriques].

2. Itration while

La commande interne while correspond litration tant que prsente dans de nombreux
langages de programmation.

Syntaxe : while suite_cmd1


do
suite_cmd2
done

La suite de commandes suite_cmd1 est excute ; si son code de retour est gal 0, alors la
suite de commandes suite_cmd2 est excute, puis suite_cmd1 est rexcute. Si son code de
retour est diffrent de 0, litration se termine.
En dautres termes, suite_cmd2 est excute autant de fois que le code de retour de
suite_cmd1 est gal 0.

Loriginalit de cette structure de contrle est que le test ne porte pas sur une condition
boolenne (vraie ou fausse) mais sur le code de retour issu de lexcution dune suite de
commandes.

En tant que mots-cl, while, do et done doivent tre les premiers mots d'une commande.

Une commande while, comme toute commande interne, peut tre crite directement sur la
ligne de commande.

Ex : $ while who | grep sanchis >/dev/null


> do
> echo lutilisateur sanchis est encore connecte
> sleep 5
> done
lutilisateur sanchis est encore connecte

^C
$

71
Le fonctionnement est le suivant : la suite de commandes who | grep sanchis est excute.
Son code de retour sera gal 0 si le mot sanchis est prsent dans les rsultats engendrs par
lexcution de la commande unix who, cest dire si lutilisateur sanchis est connect. Dans
ce cas, la ou les lignes correspondant cet utilisateur seront affiches sur la sortie standard de
la commande grep. Comme seul le code de retour est intressant et non le rsultat, la sortie
standard de grep est redirige vers le puits (/dev/null). Enfin, le message est affich et le
programme sendort pendant 5 secondes. Ensuite, la suite de commandes who | grep
sanchis est rexcute. Si lutilisateur sest totalement dconnect, la commande grep ne
trouve aucune ligne contenant la chane sanchis, son code de retour sera gal 1 et le
programme sort de litration.

Commandes internes while et deux-points

La commande interne deux-points associe une itration while compose rapidement un


serveur (dmon) rudimentaire.

Ex : $ while : => boucle infinie


> do
> who | cut -d' ' -f1 >fic => traitement effectuer
> sleep 300 => temporisation
> done &
[1] 12568 => pour arrter lexcution : kill 12568
$

Lecture du contenu dun fichier texte

La commande interne while est parfois utilise pour lire le contenu dun fichier texte. La
lecture seffectue alors ligne par ligne. Il suffit pour cela :
- de placer une commande interne read dans suite_cmd1
- de placer les commandes de traitement de la ligne courante dans suite_cmd2
- de rediriger lentre standard de la commande while avec le fichier lire.

Syntaxe : while read [ var1 ... ]


do
commande(s) de traitement de la ligne courante
done < fichier__lire

Exemple : Programme shell wh qui affiche les noms des utilisateurs connects

#!/bin/bash
# @(#) wh

who > tmp


while read nom reste
do
echo $nom
done < tmp
rm tmp

72
Exercice 4 : On dispose dun fichier personnes dont chaque ligne est constitue du prnom
et du genre (m pour masculin, f pour fminin) dun individu.

Ex : $ cat personnes
arthur m
pierre m
dominique f
paule f
sylvie f
jean m
$

Ecrire un programme shell tripersonnes qui cre partir de ce fichier, un


fichier garcons contenant uniquement les prnoms des garons et un fichier
filles contenant les prnoms des filles.

Ex : $ tripersonnes
$
$ cat filles
dominique
paule
sylvie
$
$ cat garcons
arthur
pierre
jean
$

Lorsque le fichier lire est cr par une commande cmd, comme dans le programme wh, on
peut utiliser la syntaxe :

cmd | while read [ var1 ... ]


do
commande(s) de traitement de la ligne courante
done

Exemple : programme shell wh1

#!/bin/bash
# @(#) wh1

who | while read nom reste


do
echo $nom
done

Par rapport au programme shell wh, il ny a pas de fichier temporaire tmp grer.

Exercice 5 : Un utilisateur a la possibilit denvoyer un message un autre utilisateur


connect sur la mme machine laide de la commande write.
Ecrire un programme shell acceptmess qui affiche le nom de tous les
utilisateurs connects qui acceptent les messages.

73
La commande who T indique pour chaque terminal ouvert si lutilisateur
accepte les messages (+) ou les refuse (-).

Ex : $ who -T
bond - pts/0 2013-12-02 15:53 (10.2.2.11:0.0)
sanchis + pts/1 2013-12-02 15:53 (10.2.2.11:0.0)
sanchis + pts/2 2013-12-02 15:53 (10.2.2.21:0.0)
$
$ acceptmess
sanchis
sanchis
$

Exercice 6 :

a) Ecrire un programme shell etatmess1 prenant en argument un nom dutilisateur


et affiche pour chaque terminal quil a ouvert, sil accepte (oui) ou refuse (non)
les messages. On ne considrera aucun cas d'erreur.

Ex : $ etatmess1 bond
bond pts/0 non
$

b) Modifier ce programme, soit etatmess2, pour qu'il affiche un message d'erreur


lorsque le nom de lutilisateur pass en argument nexiste pas.

c) Modifier le programme prcdent, soit etatmess, pour qu'il vrifie galement le


nombre d'arguments passs lors de l'appel.

Remarques sur la lecture dun fichier avec while

1) La lecture ligne par ligne dun fichier laide dune commande interne while est lente
et peu lgante. Il est prfrable dutiliser une suite de filtres permettant daboutir au rsultat
voulu.
Par exemple, en utilisant un filtre supplmentaire (la commande unix cut), on peut
saffranchir de litration while dans le programme wh1. Il suffit dextraire le premier champ
de chaque ligne.

La commande unix cut permet de slectionner un ou plusieurs champs de chaque ligne dun
fichier texte. Un champ peut tre spcifi en prcisant avec loption d le caractre sparateur
de champ (par dfaut, il sagit du caractre tabulation) ; les numros de champs doivent alors
tre indiqus avec loption -f.

Exemple : programme shell wh1.cut :


#!/bin/bash
# @(#) wh1.cut

who | cut -d ' ' -f1

Ex : $ wh1.cut
sanchis

74
root
$

Dans le programme wh1.cut, on prcise que la commande cut doit prendre comme sparateur
le caractre espace (-d ' ') et que seul le premier champ de chaque ligne doit tre extrait (-f1).

Lorsque le traitement effectuer sur le contenu dun fichier est plus complexe, il est
prfrable dutiliser des commandes spcialises telles que awk et sed.

2) Une deuxime raison dviter la lecture ligne ligne dun fichier avec while est
quelle peut conduire des rsultats diffrents suivant le mode de lecture choisi (tube, simple
redirection ou substitution de processus).

Prenons lexemple o lon souhaite mettre jour la valeur dune variable var aprs lecture de
la premire ligne dun fichier.
Le programme shell maj ci-dessous connecte laide dun tube la sortie standard de la
commande unix ls lentre de la commande interne while. Aprs lecture de la premire
ligne, la valeur de la variable var est modifie puis litration se termine (commande interne
break). Pourtant, cette nouvelle valeur ne sera pas affiche. En effet, lutilisation du tube a
pour effet de faire excuter litration while par un processus diffrent : il y a alors deux
instances diffrentes de la variable var : celle qui a t initialise 0 au dbut de lexcution
de maj et celle interne au nouveau processus qui initialise 1 sa propre instance de var. Aprs
terminaison de litration while, le processus qui lexcutait disparat ainsi que sa variable var
initialise 1 [cf. Chapitre 5, Redirections lmentaires, 3].

Exemple : programme shell maj :

#!/bin/bash
# @(#) maj

var=0
ls | while read
do
var=1
break
done

echo $var

Ex : $ maj
0
$

Pour rsoudre ce problme, il suffit dutiliser une substitution de processus [cf. Chapitre 5,
Redirections lmentaires, 4] la place dun tube.

Exemple : programme shell maj1 :


#!/bin/bash
# @(#) maj1

var=0
while read
do
var=1
break

75
done < <(ls)

echo $var

Ex : $ maj1
1
$

En utilisant la substitution de processus <(ls), le shell cre un fichier temporaire dans lequel
sont crites les donnes produites par lexcution de la commande unix ls. Le contenu de ce
fichier alimente ensuite lentre standard de la commande interne while laide dune
redirection <.
Lorsque lon excute le programme maj1, bash ne cre pas un nouveau processus pour
excuter litration while : il ny a quune instance de la variable var qui est convenablement
mise jour.

3) On ne doit pas utiliser le couple de commandes internes while read pour lire le
contenu dun fichier binaire.

76
Chapitre 9 : Chanes de caractres

1. Protection de caractres

1.1 Mcanismes

Le shell utilise diffrents caractres particuliers pour effectuer ses propres traitements ($ pour
la substitution, > pour la redirection de la sortie standard, * comme caractre gnrique, etc.).
Pour utiliser ces caractres particuliers comme de simples caractres, il est ncessaire de les
protger de l'interprtation du shell. Trois mcanismes sont utilisables :

Protection d'un caractre l'aide du caractre \

Ce caractre protge le caractre qui suit immdiatement le caractre \.

Ex : $ ls
tata toto
$ echo *
tata toto
$ echo \* => le caractre * perd sa signification de caractre gnrique
*
$
$ echo \\ => le deuxime caractre \ perd sa signification de caractre de protection
\
$

Remarque : dans les exemples de cette section, les caractres ou touches en vert ont perdu
leur signification particulire, les caractres ou touches en rouge sont
interprts.

Le caractre \ permet galement dter la signification de la touche Entre. Cela a pour effet
daller la ligne sans quil y ait excution de la commande. En effet, aprs saisie dune
commande, lutilisateur demande au shell lexcution de celle-ci en appuyant sur cette touche.
Annuler linterprtation de la touche Entre autorise lutilisateur crire une longue
commande sur plusieurs lignes.

Dans lexemple ci-dessous, la signification de la touche Entre a t inhibe par le caractre


\ : bash dtecte que la commande interne echo nest pas termine et affiche la chane dappel
contenue dans la variable prdfinie PS2 du shell.

Ex : $ echo coucou \Entre


> salut Entre => terminaison de la commande : le shell lexcute !
coucou salut
$

77
Protection partielle "chane"

A lintrieur dune paire de guillemets, tous les caractres de chane sauf $ \ ` " sont
protgs de l'interprtation du shell. Cela signifie, par exemple, que le caractre $ sera quand
mme interprt comme une substitution effectuer.

Ex : $ echo "< * $PWD ' >"


< * /home/sanchis ' >
$
$ echo "\"$PS2\""
"> " => valeur de la variable prdfinie PS2 entre guillemets
$

Protection totale 'chane'

Entre une paire dapostrophes ('), aucun caractre de chane (sauf le caractre ') n'est
interprt.

Ex : $ echo '< * $PWD " >'


< * $PWD " >
$

Lutilisation du caractre apostrophe peut provoquer lerreur suivante.

Ex : $ echo c'est lundi


> => le shell interprte lapostrophe comme un dbut de chane
>' => protger et attend par consquent la deuxime apostrophe
cest lundi

Pour viter cela, on peut supprimer la signification particulire de cette apostrophe ou bien
utiliser une paire de guillemets.

Ex : $ echo N\'oublie pas !


N'oublie pas !
$
$ echo "c'est lundi"
c'est lundi
$

1.2 Exemples dutilisation

Certaines commandes unix telles que find utilisent pour leur propre fonctionnement les
mmes caractres gnriques que ceux du shell. Utiliss sans prcaution, ces caractres
provoquent le plus souvent une erreur dexcution. Par exemple, la commande
find . -name *.py print
recherche partir du rpertoire courant et affiche (ou plutt devrait afficher) tous les noms
dentres se terminant par la chane .py.

Ex : $ ls -l
total 20
-rw-r--r-- 1 sanchis sanchis 1280 oct. 5 2010 cliTCP.py

78
drwxr-xr-x 2 sanchis sanchis 4096 oct. 5 2010 Divers
-rwxr--r-- 1 sanchis sanchis 117 oct. 5 2010 ou
-rwxr--r-- 1 sanchis sanchis 117 oct. 5 2010 ou0
-rw-r--r-- 1 sanchis sanchis 2397 oct. 5 2010 servTCP.py
$
$ find . -name *.py -print
find: les chemins doivent prcder l'expression : servTCP.py
Utilisation : find [-H] [-L] [-P] [-Olevel] [-D
help|tree|search|stat|rates|opt|exec] [chemin...] [expression]
$

Lorigine du problme est que le caractre * aurait d tre interprt par la commande find
alors quil a t interprt par bash, ce qui a conduit lexcution de la commande
find . -name cliTCP.py servTCP.py print
La commande find signale une erreur de syntaxe car elle nattend quune seule chane aprs
son option name.

Pour corriger le problme, il suffit de protger le caractre * de linterprtation de bash.

Ex : $ find . -name "*.py" -print


./servTCP.py
./cliTCP.py
$

Dans ce cas de figure, le type de protection utilis na pas dimportance : on aurait galement
pu crire '*.py' ou \*.py.

La prsence de caractres espace (ou de caractres spciaux de bash) dans la valeur dun
paramtre (variable ou paramtre de position) peut poser problme lorsque cette valeur
participe lexcution dune commande.

Soit le programme shell nblig0 qui affiche le nombre de lignes (commande wc l) dun fichier
dont le nom est saisi par lutilisateur et contenu dans la variable rep.

#!/bin/bash
# @(#) nblig0

read -p "Saisissez un nom d'entree : " rep


wc -l $rep

Ex : $ ls -l
total 12
-rw-r--r-- 1 sanchis sanchis 1728 nov. 1 2010 Meteo du jour.txt
-rwxr--r-- 1 sanchis sanchis 83 nov. 1 2010 nblig
-rwxr--r-- 1 sanchis sanchis 82 nov. 1 2010 nblig0
$
$ nblig0
Saisissez un nom d'entree : Meteo du jour.txt
wc: Meteo: Aucun fichier ou dossier de ce type
wc: du: Aucun fichier ou dossier de ce type
wc: jour.txt: Aucun fichier ou dossier de ce type
0 total
$

La variable rep contient bien la chane Meteo du jour.txt mais aprs substitution de $rep, la
commande qui sera finalement excute est : wc l Meteo du jour.txt

79
La commande unix wc nest pas excute avec un seul argument mais avec trois. Chacun
deux est considr par wc comme un nom de fichier qui, absent, provoque une erreur
dexcution.

La solution ce problme consiste prserver lintgrit de la valeur de la variable rep aprs


que la substitution ait t effectue par le shell. On utilise pour cela la syntaxe "$rep".
Il est noter que la syntaxe '$rep' aurait t inadquate car elle interdit au shell deffectuer la
substitution $rep.

Ex : $ cat nblig
#!/bin/bash
# @(#) nblig

read -p "Saisissez un nom d'entree : " rep


wc -l "$rep"

$
$ nblig
Saisissez un nom d'entree : Meteo du jour.txt
35 Meteo du jour.txt
$

De manire gnrale, il est fortement conseill de prserver lintgrit dune chane de


caractres obtenue aprs une substitution, surtout lorsque lon ne connait pas lavance la
composition de cette chane.

Cette politique est systmatiquement suivie dans lcriture des programmes shell qui
accompagnent linterprteur bash (ex : .bashrc, .profile).

Ex : $ cat ~/.profile
# ~/.profile: executed by the command interpreter for login shells.
# . . .

# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi

# set PATH so it includes user's private bin if it exists


#if [ -d "$HOME/bin" ] ; then
# PATH="$HOME/bin:$PATH"
#fi
$

Les fichiers shell .bashrc et .profile permettent lutilisateur de configurer son


environnement de travail [cf. Chapitre 1, Introduction Bash, 1.1]. Ces deux fichiers sont
prsents dans le rpertoire de connexion de lutilisateur dont le chemin peut tre rapidement
dsign par le caractre ~.

Avant quune syntaxe spcifique ne soit introduite dans bash, le mcanisme dindirection
[cf. Chapitre 2, Substitution de paramtres, 6] tait obtenu laide de la commande interne
eval et des caractres de protection du shell.

80
La syntaxe de cette commande interne est la suivante : eval [ arg ... ]

La commande interne eval interprte au sens du shell (substitution de paramtres, etc.) chacun
de ses arguments arg puis concatne la chane rsultante en une seule chane. Celle-ci est
ensuite nouveau interprte et excute comme une commande par le shell.
En dautres termes, eval permet deffectuer une interprtation en deux passes.

Ex : $ var=v1
$ v1=un
$ eval echo \$$var
un
$

Lors de la premire passe, le premire caractre $ nest pas interprt car il est protg de
linterprtation du shell (\$) et la chane $var est remplace par la valeur de la variable var. A
lissu de la premire interprtation, on obtient la chane suivante : echo $v1
Cette chane est ensuite interprte comme commande par bash.

Une autre manire de procder est la suivante :


$ var=\$v1
$ v1=un
$
$ eval echo $var
un
$

Cette formulation permet de gnraliser le mcanisme et dobtenir une indirection multi


niveau.

Ex : $ var=\$v1
$ v1=\$v2
$ v2=\$v3
$ v3=trois
$
$ eval eval eval echo $var
trois
$

Les interprtations successives donnent les rsultats suivants :


$ echo $var
$v1
$ eval echo $var
$v2
$ eval eval echo $var
$v3
$
$ eval eval eval echo $var
trois
$

2. Longueur d'une chane de caractres


Syntaxe : ${#paramtre}

81
Cette syntaxe est remplace par la longueur de la chane de caractres contenue dans
paramtre. Ce dernier peut tre une variable, un paramtre spcial ou un paramtre de
position.

Ex : $ echo $PWD
/home/sanchis
$ echo ${#PWD}
13 => longueur de la chane /home/sanchis
$
$ set "au revoir"
$ echo ${#1}
9 => la valeur de $1 tant au revoir, sa longueur est 9
$
$ ls >/dev/null
$
$ echo ${#?}
1 => contenue dans $?, la valeur du code de retour de ls
$ => est 0, par consquent la longueur de cette chane est 1

3. Modificateurs de chanes
Les modificateurs de chanes permettent la suppression d'une sous-chane de caractres
correspondant un modle exprim l'aide de caractres ou dexpressions gnriques.

Suppression de la plus courte sous-chane gauche

Syntaxe : ${paramtre#modle}

Ex : $ echo $PWD
/home/sanchis
$
$ echo ${PWD#*/}
home/sanchis => le premier caractre / a t supprim
$
$ set "82a34a"
$
$ echo ${1#*a}
34a => suppression de la sous-chane 82a
$

Suppression de la plus longue sous-chane gauche

Syntaxe : ${paramtre##modle}

Ex : $ echo $PWD
/home/sanchis
$
$ echo ${PWD##*/}
sanchis => suppression de la plus longue sous-chane gauche se

82
$ => terminant par le caractre /
$ set 72a34ab
$
$ echo ${1##*a}
b
$

Suppression de la plus courte sous-chane droite

Syntaxe : ${paramtre%modle}

Ex: $ echo $PWD


/home/sanchis
$ echo ${PWD%/*} => suppression de la sous-chane /sanchis
/home
$

Suppression de la plus longue sous-chane droite

Syntaxe : ${paramtre%%modle}

Dans lexemple ci-dessous, la variable eleve contient les prnom, nom et diverses notes d'un
lve. Les diffrents champs sont spars par un caractre deux-points. Il peut manquer des
notes un lve (cela se caractrise par un champ vide).

Ex : $ eleve="Pierre Dupont::12:10::15:9"
$
$ echo ${eleve%%:*} => extraction du prnom et nom
Pierre Dupont
$

Exercice 1 : En utilisant les modificateurs de chanes,

a) Ecrire un programme shell touslesutil qui lit le contenu du fichier /etc/passwd


(utilisation de la syntaxe while read) et affiche le nom des utilisateurs
enregistrs (1er champ du fichier).

b) Modifier ce programme (soit touslesutiluid) pour quil affiche le nom et luid


de chaque utilisateur (1er et 3me champs).

Exercice 2 : En utilisant les modificateurs de chanes,

a) Ecrire un programme shell basenom ayant un fonctionnement similaire la


commande unix basename. Cette commande affiche le dernier lment dun
chemin pass en argument. Il n'est pas ncessaire que ce chemin existe
rellement.

Ex : $ basename /toto/tata/tutu
tutu
$

83
b) Si un suffixe est mentionn comme deuxime argument, celui-ci est galement
t de l'lment par la commande basename.

Ex : $ basename /toto/tata/tutu/prog.c .c
prog
$

Ecrire un programme basenom1 qui se comporte de la mme manire.

4. Extraction de sous-chanes

${paramtre:ind} : extrait de la valeur de paramtre la sous-chane dbutant


l'indice ind. La valeur de paramtre nest pas modifie.

Attention : l'indice du premier caractre d'une chane est 0

Ex : $ ch="abcdefghijk"
$ # 01234567..10
$
$ echo ${ch:3}
defghijk
$

${paramtre:ind:nb} : extrait nb caractres partir de l'indice ind

Ex : $ echo ${ch:8:2}
ij
$ set ABCDEFGH
$
$ echo ${1:4:3}
EFG
$

Ces deux syntaxes extraient des sous-chanes uniquement partir de leur position. La
commande unix expr, plus gnrale, permet dextraire une sous-chane suivant un modle
exprim sous la forme dune expression rgulire.

Exercice 3 :

a) Ecrire un programme calibre prenant deux arguments, une chane de caractres


ch et un nombre nb, qui affiche les nb premiers caractres de ch. Aucune erreur
ne doit tre traite.

b) Modifier le programme prcdent, soit calibre1, pour quil vrifie que :


- le nombre darguments est correct
- le deuxime argument est un nombre (suite non vide de chiffres).

84
5. Remplacement de sous-chanes

${paramtre/mod/ch} : bash recherche dans la valeur de paramtre la plus longue sous-


chane satisfaisant le modle mod puis remplace cette sous-
chane par la chane ch. Seule la premire sous-chane trouve
est remplace. La valeur de paramtre nest pas modifie.
Caractres et expressions gnriques peuvent tre prsents dans
mod.
Ce mcanisme de remplacement comprend plusieurs aspects :

(1) Remplacement de la premire occurrence

Ex : $ v=totito
$ echo ${v/to/lo}
lotito
$

La valeur de la variable v (totito) contient deux occurrences du modle to. Seule la


premire occurrence est remplace par la chane lo.

Ex : $ set topo
$ echo $1
topo
$
$ echo ${1/o/i}
tipo
$

(2) Remplacement de la plus longue sous-chane

Ex : $ v=abcfefg
$ v1=${v/b*f/toto} => utilisation du caractre gnrique *
$ echo $v1
atotog
$

Deux sous-chanes de v satisfont le modle b*f : bcf et bcfef


Cest la plus longue qui est remplace par toto.

${paramtre//mod/ch} : contrairement la syntaxe prcdente, toutes les occurrences


(et non seulement la premire) satisfaisant le modle mod sont
remplaces par la chane ch

Ex : $ var=tobatoba
$ echo ${var//to/tou}
toubatouba
$
$ set topo
$ echo $1
topo
$
$ echo ${1//o/i}

85
tipi
$

${paramtre/mod/}
${paramtre//mod/} : suivant la syntaxe utilise, lorsque la chane ch est absente, la
premire ou toutes les occurrences satisfaisant le modle mod
sont supprimes

Ex : $ v=123azer45ty
$ shopt s extglob
$ echo ${v//+([[:lower:]])/}
12345
$

Lexpression gnrique +([[:lower:]] dsigne la plus longue suite non vide de


minuscules. La syntaxe utilise signifie que toutes les occurrences doivent tre
traites : la variable v contient deux occurrences (azer et ty) satisfaisant le modle. Le
traitement effectuer est la suppression.

Si on le souhaite, il est possible de prciser loccurrence cherche en dbut de chane de


paramtre (syntaxe utiliser : #mod) ou bien en fin de chane (%mod).

Ex : $ v=automoto
$ echo ${v/#aut/vel}
velomoto
$
$ v=automoto
$ echo ${v/%to/teur}
automoteur
$

6. Transformation en majuscules/minuscules
${paramtre^^} : transforme la valeur de paramtre en majuscules.
Les caractres autres que les minuscules ne sont pas modifis.

Ex : $ a=bonjour
$
$ echo ${a^^}
BONJOUR
$
$ a=aB,c:D
$
$ echo ${a^^}
AB,C:D
$
$ set un dEuX:: trois
$
$ echo ${2^^}
DEUX::
$

Pour que la valeur dune variable var soit toujours en majuscules, on utilise la commande
interne : declare u var

86
Ex : $ declare -u x
$
$ x=coucou
$
$ echo $x
COUCOU
$
$ x=aB,c:D
$
$ echo $x
AB,C:D
$

${paramtre,,} : transforme la valeur de paramtre en minuscules.


Les caractres autres que les majuscules ne sont pas modifis.

Ex : $ b="CouCOU :)"
$
$ echo ${b,,}
coucou :)
$
$ set Un,uN deux trois
$
$ echo ${1,,}
un,un
$

Pour que la valeur dune variable var soit toujours en minuscules, on utilise la commande
interne : declare l var

Ex : $ declare -l y
$
$ y=COUCoU
$
$ echo $y
coucou
$
$ y='COU COU Cou !'
$
$ echo $y
cou cou cou !
$

7. Formatage de chanes
Lorsque lon souhaite afficher une chane de caractres sur la sortie standard, il est dusage
dutiliser echo, commande interne historique des premiers shells. Pourtant, echo souffre de
plusieurs handicaps :
- au cours du temps, diffrentes versions de cette commande interne ont vu le jour,
ayant la fois des syntaxes et des comportements diffrents
- le formatage des chanes afficher est malais.
Lintrt de la commande interne printf est quelle ne prsente pas ces inconvnients. Issue
directement de la fonction printf de la bibliothque standard du langage C, elle en partage les
principales caractristiques.

87
Sa syntaxe est la suivante : printf chane_format [ argument1 ]

Comme sa consur du langage C, chane_format est constitue de caractres littraux et de


spcificateurs de format. Les caractres littraux seront affichs tels quels sur la sortie
standard tandis que les spcificateurs, introduits laide du caractre %, indiqueront la fois
le type et le formatage utiliser pour afficher les arguments qui suivent chane_format.
Pour provoquer un retour la ligne, il faudra galement utiliser la squence dchappement \n.

Pour que printf fonctionne correctement, il est fortement conseill de fournir autant
darguments quil y a de spcificateurs dans chane_format.

Drivant de la fonction C printf, les possibilits syntaxiques offertes sont trop riches pour tre
compltement dtailles1. Cest pourquoi seuls quelques spcificateurs seront prsents.

Les types pris en compte sont les entiers (%d), les rels (%f), les chanes (%s) et les
caractres (%c).
$ printf "%d kilo(s) de %s (categorie %c) a %f euros l'unite\n" 2 fruits A 3,45
2 kilo(s) de fruits (categorie A) a 3,450000 euros l'unite
$

Suivant la reprsentation souhaite, il existe plusieurs spcificateurs pour un mme type. Par
exemple, pour le type des rels, on peut utiliser le spcificateur %f (notation usuelle) ou %e
(notation scientifique). Le spcificateur %g vite laffichage des 0 superflus.
$ printf "%f ou %e\n" 13,45 13,45
13,450000 ou 1,345000e+01
$
% printf "%g %g\n" 13,4500 3,450000e+01
13,45 34,5
$

Entre le caractre % et lindicateur de conversion tel que d, f, etc. peuvent tre mentionns
diffrents attributs qui affineront la reprsentation affiche. Par exemple,
%10d : affiche lentier sur 10 caractres. Par dfaut, la justification est droite.

$ printf "'%10d'\n" 123


' 123'
$

%-20s : justifie la chane gauche sur 20 caractres.

$ printf "'%20s'\n" coucou


' coucou'
$ printf "'%-20s'\n" coucou
'coucou '
$

La justification gauche est galement utilisable avec les autres types.

$ printf "'%-10d'\n" 123

1
Lexcution des commandes man 1 printf et man 3 printf permet de se faire une ide plus prcise des
possibilits offertes par la commande interne printf.

88
'123 '
$

Si la longueur spcifie est trop courte pour laffichage, elle est ignore. La
valeur mentionne correspond en fait un nombre minimal de caractres
afficher.

$ printf "'%2s'\n" coucou


'coucou'
$

Si la place dune longueur numrique on utilise le caractre *, cest


largument qui prcde largument afficher qui sera interprt comme la
longueur daffichage.

$ read -p "longueur d'affichage : " gabarit


longueur d'affichage : 10
$
$ printf "'%*d'\n" ${gabarit} 123
' 123' => affichage sur 10 caractres
$
$ read -p "longueur d'affichage : " gabarit
longueur d'affichage : 5
$
$ printf "'%-*s'\n" ${gabarit} cou
'cou ' => affichage sur 5 caractres
$

%.3f : un nombre situ aprs un caractre point indique la prcision souhaite. Pour
un nombre rel, il sagit du nombre de chiffres aprs la virgule afficher.

$ printf "%.3f\n" 12,34589


12,346
$
$ printf "%.3f\n" 2,34
2,340
$

Si la prcision est applique une chane de caractres, elle sera interprte


comme un nombre maximal de caractres afficher.

$ printf "%.3s\n" coucou


cou
$

Certains caractres non imprimables (ex : le caractre interligne) disposent dune squence
dchappement (ex : \n) qui facilite leur utilisation. Quelques exemples de squences
dchappement reconnues sont : \t (tabulation horizontale), \r (retour chariot), \a (bip).

$ printf "\tcoucou\n"
coucou
$

Enfin, loption v de printf permet daffecter une variable, une chane formate par cette
commande interne. Dans ce cas, la chane rsultat nest pas affiche.

89
Ex : $ printf -v util "prenom:%-10s/taille:%.2f" Pierre 1,8345
$
$ echo "$util"
prenom:Pierre /taille:1,83
$

8. Gnration de chanes de caractres


Bash offre la possibilit de crer automatiquement une liste de chanes de caractres laide
de la syntaxe gnrale suivante :

[prfixe]{chane1,[chane2 ]}[suffixe]

Entre la paire daccolades, les chanes doivent tre spares par une virgule (pas de caractre
espace par exemple). Au moins un caractre virgule doit tre prsent entre les accolades.

Ce mcanisme de substitution trs particulier prend tout son sens lorsquil est utilis avec un
prfixe : prfixe{chane1,chane2 }
La chane rsultat est alors constitue de toutes les combinaisons <prfixe><chanei>
possibles. Cette syntaxe est utilise, par exemple, pour crer en une seule commande une suite
de rpertoires en mentionnant une seule fois le chemin du rpertoire destination.

Ex : $ mkdir p Projets/P1/{src,include,bin}
$
$ ls -l Projets/P1
total 12
drwxrwxr-x 2 sanchis sanchis 4096 avril 1 08:07 bin
drwxrwxr-x 2 sanchis sanchis 4096 avril 1 08:07 include
drwxrwxr-x 2 sanchis sanchis 4096 avril 1 08:07 src
$

Loption p de la commande unix mkdir cre les rpertoires Projets et P1 sils nexistaient
pas.

Loption braceexpand de la commande interne set permet dactiver ou dinhiber la


substitution daccolades.

Ex : $ set -o | grep braceexpand


braceexpand on => le mcanisme est dj activ
$
$ set +o braceexpand => dsactivation
$
$ echo {coucou,}
{coucou,}
$

90
Chapitre 10 : Structures de contrle for et if

1. Itration for
L'itration for possde plusieurs syntaxes dont les deux plus gnrales sont :

Premire forme : for var


do
suite_de_commandes
done

Lorsque cette syntaxe est utilise, la variable var prend successivement la valeur de chaque paramtre
de position initialis.

Exemple : programme shell for_arg


#!/bin/bash

for i
do
echo $i
echo "Passage a l'argument suivant ..."
done

Ex : $ for_arg un deux => deux paramtres de position initialiss


un
Passage a l'argument suivant ...
deux
Passage a l'argument suivant ...
$

Exercice 1 : Ecrire un programme shell uid_gene prenant un nombre quelconque de noms


d'utilisateurs et qui affiche pour chacun d'eux son uid. Ce dernier peut tre obtenu
directement laide de la commande : id -u nomutilisateur

Ex : $ uid_gene root sanchis


root 0
sanchis 1002
$

La commande compose for traite les paramtres de position sans tenir compte de la manire dont ils
ont t initialiss (lors de lappel dun programme shell ou bien par la commande interne set).

Exemple : programme shell for_set


-----------------
#!/bin/bash

91
set $(date)

for i
do
echo $i
done
-----------------

Ex : $ for_set
mardi
1
avril
2014,
09:10:06
(UTC+0200)
$

Deuxime forme : for var in liste_mots


do
suites_de_commandes
done

La variable var prend successivement la valeur de chaque mot de liste_mots.

Exemple : programme shell for_liste


---------------------
#!/bin/bash

for a in toto tata


do
echo $a
done
---------------------

Ex : $ for_liste
toto
tata
$

Si liste_mots contient des substitutions, elles sont pralablement traites par bash.

Exemple : programme shell affich.ls


-------------------------
#!/bin/bash

for i in /tmp $(pwd)


do
echo --- $i ---
ls $i
done
-------------------------

92
Ex : $ affich.ls
--- tmp ---
gamma
--- /home/sanchis/Rep ---
affich.ls alpha beta tmp
$

Exercice 2 : Ecrire un programme shell lsrep ne prenant aucun argument, qui demande
l'utilisateur de saisir une suite de noms de rpertoires et qui affiche leur contenu
respectif.

2. Choix if
2.1 Fonctionnement

La commande interne if implante le choix alternatif.

Syntaxe : if suite_de_commandes1
then
suite_de_commandes2
[ elif suite_de_commandes ; then suite_de_commandes ] ...
[ else suite_de_commandes ]
fi

Le fonctionnement est le suivant : suite_de_commandes1 est excute ; si son code de retour est gal
0, alors suite_de_commandes2 est excute sinon c'est la branche elif ou la branche else qui est
excute, si elle existe.

Exemple : programme shell rm1


#!/bin/bash

if rm "$1" 2> /dev/null


then echo $1 a ete supprime
else echo $1 n\'a pas ete supprime
fi

Ex : $ >toto => cration du fichier toto


$
$ rm1 toto
toto a ete supprime
$
$ rm1 toto
toto n'a pas ete supprime
$

Lorsque la commande rm1 toto est excute, si le fichier toto est effaable, le fichier est
effectivement supprim, la commande unix rm renvoie un code de retour gal 0 et cest la suite de

93
commandes qui suit le mot-cl then qui est excute ; le message toto a ete supprime est affich sur
la sortie standard.
Si toto nest pas effaable, lexcution de la commande rm choue ; celle-ci affiche un message sur la
sortie standard pour les messages derreur que lutilisateur ne voit pas car celle-ci a t redirige vers
le puits, puis renvoie un code de retour diffrent de 0. Cest la suite de commandes qui suit else qui
est excute : le message toto na pas ete supprime saffiche sur la sortie standard.

Les mots if, then, else, elif et fi sont des mots-cl. Par consquent, pour indenter une structure if
suivant le style langage C , on pourra lcrire de la manire suivante :

if suite_de_commandes1 ; then
suite_de_commandes2
else
suite_de_commandes ]
fi

La structure de contrle doit comporter autant de mots-cls fi que de if (une branche elif ne doit pas
se terminer par un fi).

Ex : if ... if ...
then ... then ...
elif ... else if ...
then ... then ...
fi fi
fi

Dans une succession de if imbriqus o le nombre de else est infrieur au nombre de then, le mot-cl
fi prcise lassociation entre les else et les if.

Ex : if ...
then ...
if ...
then ...
fi
else ...
fi

2.2 Commande compose [[

La commande interne compose [[ est souvent utilise avec la commande interne compose if. Elle
permet lvaluation dexpressions conditionnelles portant sur des objets aussi diffrents que les
permissions sur une entre, la valeur dune chane de caractres ou encore ltat dune option de la
commande interne set.

Syntaxe : [[ expr_cond ]]

Les deux caractres crochets doivent tre colls et un caractre sparateur doit tre prsent de part et
dautre de expr_cond. Les mots [[ et ]] sont des mots-cl.

94
Le fonctionnement de cette commande interne est le suivant : lexpression conditionnelle expr_cond
est value et si sa valeur est Vrai, alors le code de retour de la commande interne [[ est gal 0. Si
sa valeur est Faux, le code de retour est gal 1. Si expr_cond est mal forme ou si les caractres
crochets ne sont pas colls, une valeur diffrente est retourne.

La commande interne [[ offre de nombreuses expressions conditionnelles ; cest pourquoi, seules les
principales formes de expr_cond seront prsentes, regroupes par catgories.

. Permissions :

-r entre vraie si entre existe et est accessible en lecture par le processus courant.
-w entre vraie si entre existe et est accessible en criture par le processus courant.
-x entre vraie si le fichier entre existe et est excutable par le processus courant ou si
le rpertoire entre existe et le processus courant possde la
permission de passage.

Ex : $ echo coucou > toto


$
$ chmod 200 toto
$ ls -l toto
--w------- 1 sanchis sanchis 7 avril 1 09:14 toto
$
$ if [[ -r toto ]]
> then cat toto
> fi
$ => aucun affichage donc toto nexiste pas ou nest pas accessible en lecture,
$ => dans le cas prsent, il est non lisible
$
$ echo $?
0 => code de retour de la commande interne if
$

Mais,
$ [[ -r toto ]]
$
$ echo $?
1 => code de retour de la commande interne [[
$

. Types d'une entre :

-f entre vraie si entre existe et est un fichier ordinaire


-d entre vraie si entre existe et est un rpertoire

Exemple : programme shell affic


#!/bin/bash

if [[ -f "$1" ]]
then
echo "$1" : fichier ordinaire

95
cat "$1"
elif [[ -d "$1" ]]
then
echo "$1" : repertoire
ls "$1"
else
echo "$1" : type non traite
fi

Ex : $ affic . => traitement du rpertoire courant


. : repertoire
affic err Exercices for_liste for_set rm1 testval
$

. Renseignements divers sur une entre :

-a entre vraie si entre existe


-s entre vraie si entre existe et sa taille est diffrente de 0
Rq : la taille dun rpertoire vide est toujours
diffrente de 0

entre1 -nt entre2 vraie si entre1 existe et sa date de modification est plus rcente
que celle de entre2
entre1 -ot entre2 vraie si entre1 existe et est plus ancienne que celle de entre2

Ex : $ > err => cration dun fichier err vide


$
$ ls -l err
-rw-rw-r-- 1 sanchis sanchis 0 avril 1 08:35 err
$
$ if [[ -a err ]]
> then echo err existe
> fi
err existe
$
$ if [[ -s err ]]
> then echo le contenu du fichier err est non vide
> else echo son contenu est vide
> fi
son contenu est vide
$

Exercice 3 : Ecrire un programme shell vide prenant un nom de rpertoire en argument et qui
indique sil est vide ou non vide.
Indication : on pourra utiliser loption A de la commande ls.

. Longueur dune chane de caractres :

-z ch vraie si la longueur de la chane ch est gale zro


ch (ou bien -n ch) vraie si la longueur de la chane ch est diffrente de zro

96
Ex : $ a= => la variable a est dfinie et est vide
$
$ if [[ -z $a ]]
> then echo la longueur de a est egale a 0
> fi
la longueur de a est egale a 0
$
$ echo $#
0 => aucun paramtre de position nest initialis
$
$
$ if [[ -z $1 ]]
> then echo la longueur est egale a 0
> fi
la longueur est egale a 0
$

. Comparaisons de chanes de caractres :

ch1 < ch2 vraie si ch1 prcde ch2


ch1 > ch2 vraie si ch1 suit ch2

Lordre des chanes ch1 et ch2 est command par la valeur des paramtres rgionaux.

Ex : $ a=bonjour A=Bonjour
$
$ if [[ $a < $A ]]
> then echo $a precede $A
> elif [[ $a > $A ]]
> then echo $a suit $A
> else echo elles sont egales
> fi
bonjour precede Bonjour
$

ch == mod vraie si la chane ch correspond au modle mod


ch != mod vraie si la chane ch ne correspond pas au modle mod

mod est un modle de chanes pouvant contenir caractres et expressions gnriques. Ces derniers ne
doivent pas tre protgs de linterprtation de bash lorsquils sont placs entre les caractres [[ ]].

Ex : $ a="au revoir"
$
$ [[ $a == 123 ]] => faux
$
$ echo $?
1
$
$ [[ $a == a* ]] => vrai : la valeur de a commence par le caractre a ; on
$ => peut remarquer la non protection du caractre *
$ echo $?
0
$

97
$ b=123
$
$ if [[ $b == +([[:digit:]]) ]]
> then
> echo "c'est une suite de chiffres"
> fi
c'est une suite de chiffres
$
$ c=BonJOuR
$
$ shopt -s nocasematch => minuscules et majuscules ne sont pas
$ => distingues
$ [[ $c == bonjour ]]
$
$ echo $?
0 => la valeur de la variable c correspond au modle bonjour
$

Si ch ou mod ne sont pas dfinies, la commande interne [[ ne provoque pas derreur de syntaxe.

Exemple : programme shell testval


#!/bin/bash

if [[ "$1" == "$a" ]]
then echo OUI
else echo >&2 NON
fi

Ex : $ testval coucou
NON => dans testval, $1 est remplac par coucou, la variable a nest
$ => pas dfinie
$ testval
OUI => aucun des deux membres de lgalit nest dfini
$
$ a=bonjour testval bonjour => la variable a est locale au fichier shell testval,
OUI => elle est initialise lors de lappel du fichier shell
$

Remarque : il existe un oprateur =~ qui permet de mettre en correspondance une chane de


caractre ch avec une expression rgulire expr_reg : ch =~ expr_reg
Contrairement aux caractres et expressions gnriques, les expressions rgulires ne
sont pas spcifiques bash.

Exercice 4 :

a) Ecrire un programme shell minchaines prenant au moins une chane de caractres en


argument et qui affiche la plus petite (au sens lexicographique).
Aucun cas derreur ne doit tre trait.

98
b) Modifier ce programme pour quil vrifie quil y a au moins un argument et quaucun
argument nest la chane vide ("").

. Etat dune option :

-o opt vraie si ltat de loption opt de la commande interne set est on

Ex : $ set -o | grep noglob


noglob off
$
$ if [[ -o noglob ]]; then echo ON
> else echo OFF
> fi
OFF
$

. Composition d'expressions conditionnelles :

( expr_cond ) vraie si expr_cond est vraie. Permet le regroupement dexpressions


conditionnelles
! expr_cond vraie si expr_cond est fausse

expr_cond1 && expr_cond2 vraie si les deux expr_cond sont vraies. Lexpression
expr_cond2 nest pas value si expr_cond1 est fausse.

expr_cond1 || expr_cond2 vraie si une des deux expr_cond est vraie. Lexpression
expr_cond2 nest pas value si expr_cond1 est vraie.

Les quatre oprateurs ci-dessus ont t lists par ordre de priorit dcroissante.

Ex : $ ls -l /etc/at.deny
-rw-r----- 1 root daemon 144 oct. 25 2011 /etc/at.deny
$
$ if [[ ! ( -w /etc/at.deny || -r /etc/at.deny ) ]]
> then
> echo OUI
> else
> echo NON
> fi
OUI
$

Le fichier /etc/at.deny nest accessible ni en lecture ni en criture pour lutilisateur sanchis ; le code
de retour de la commande interne [[ sera gal 0 car lexpression conditionnelle globale est vraie.

Attention : il ne faut pas confondre les oprateurs ! && || utiliss par la commande interne [[ pour
construire les expressions conditionnelles et ces mmes oprateurs ! && || portant sur
les codes de retour [cf. Chapitre 7, Code de retour].

99
En combinant commande interne [[, oprateurs sur les codes de retour et regroupements de
commandes, lutilisation dune structure if devient inutile.

Ex : $ ls -l toto
--w------- 1 sanchis sanchis 7 mai 28 14:26 toto
$
$ [[ -r toto ]] || {
> echo >&2 "Probleme de lecture sur toto"
> }
Probleme de lecture sur toto
$

Remarque : par souci de portabilit, bash intgre galement lancienne commande interne [. Celle-
ci possde des fonctionnalits similaires celles de [[ mais est plus dlicate utiliser.

Ex : $ a="au revoir"
$
$ [ $a = coucou ] => loprateur galit de [ est le symbole =
bash: [: trop d'arguments
$

Le caractre espace prsent dans la valeur de la variable a provoque une erreur de


syntaxe. Il est ncessaire de prendre davantage de prcaution quand on utilise cette
commande interne.

Ex : $ [ "$a" = coucou ]
$
$ echo $?
1
$

100
Chapitre 11 : Entiers et expressions arithmtiques

1. Variables de type entier


Pour dfinir et initialiser une ou plusieurs variables de type entier, on utilise la syntaxe suivante :

declare -i nom[=expr_arith] [ nom[=expr_arith] ... ]

Ex : $ declare -i x=35 => dfinition et initialisation de la variable entire x


$
$ declare -i v w => dfinition des variables entires v et w
$
$ v=12 => initialisation de v par affectation
$
$ read w
34 => initialisation de w par lecture
$

Rappel : il n'est pas ncessaire de dfinir une variable avant de l'utiliser !

Pour que la valeur dune variable entire ne soit pas accidentellement modifie aprs quelle ait t
initialise, il suffit dajouter lattribut r.

Ex : $ declare -ir b=-6


$
$ b=7
bash: b : variable en lecture seule => seule la consultation est autorise !
$

Enfin, pour connatre toutes les variables entires dfinies, il suffit dutiliser la commande :
declare i

Ex : $ declare -i
declare -ir BASHPID
declare -ir EUID="1000"
declare -i HISTCMD
declare -i LINENO
declare -i MAILCHECK="60"
declare -i OPTIND="1"
declare -ir PPID="20391"
declare -i RANDOM
declare -ir UID="1000"
declare -ir b="-6"
declare -i v="12"
declare -i w="34"
declare -i x="35"
$

2. Reprsentation dune valeur de type entier


Comme en langage C, un littral entier (valeur de type entier) qui ne commence pas par le chiffre 0
est considr comme tant exprim en base dcimale (ex : 11, -234). Un littral qui commence par

101
le chiffre 0 est interprt comme un nombre octal (ex : 071). Sil dbute par 0x ou 0X, il est
interprt comme un nombre hexadcimal (ex : 0xA, 0X0d) : les minuscules et majuscules ne sont
pas distingues.

Bash permet dexprimer des nombres dans une base allant de 2 64. On utilise pour cela la
syntaxe : base#a
Toutefois, les rsultats seront exprims en base dcimale.

Ex : $ declare -i a="023 + 3#11"


$
$ echo $a
23 => le rsultat est exprim en base 10
$
$ echo 3#$a
3#23 => tentative infructueuse pour exprimer le rsultat en base 3 !
$

La commande interne printf accepte en arguments des entiers exprims en base 10, 8 ou 16.

Ex : $ printf "%d %d %d\n" 23 023 0x23


23 19 35 => valeurs exprimes en dcimal
$

Inversement, elle est capable dafficher une valeur directement dans une de ces trois bases.
Dans la chane format de printf, on utilise la syntaxe :
%d pour afficher en dcimal un entier quelconque
%u pour afficher en dcimal un entier non sign
%o pour afficher en octal un entier non sign
%x ou %X pour afficher en hexadcimal un entier non sign

Ex : $ printf "%o\n" 23
27 => valeur dcimale 23 exprime en octal
$

Exercice 1 : Ecrire un convertisseur h2d prenant en argument un entier exprim en hexadcimal


et qui affiche sa reprsentation en dcimal. On supposera que largument est une
valeur hexadcimale correcte.

Ex : $ h2d 0x34e5F
216671
$
$ h2d 0X12
18
$

Exercice 2 : Ecrire un convertisseur d2h prenant en argument un entier en base 10 positif ou nul
et qui affiche sa reprsentation en hexadcimal. On supposera que largument est une
valeur dcimale correcte.

Ex : $ d2h +10
a
$

102
$ d2h 156
9c
$

3. Intervalles dentiers
Pour spcifier un intervalle dentiers, on utilise la syntaxe : {n1..n2[..pas]}
Les bornes de lintervalle sont n1 et n2. Le shell remplace cette syntaxe par la liste des nombres
entiers compris entre n1 et n2 inclus. Par dfaut, le pas dincrmentation est 1 (ou -1 si n1 > n2).

Ex : $ echo {4..23}
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
$
$ echo {5..-7}
5 4 3 2 1 0 -1 -2 -3 -4 -5 -6 -7
$

Il est possible dajouter un ou plusieurs 0 devant les bornes pour que laffichage de chaque valeur
seffectue avec le mme nombre de caractres.

Ex : $ echo {04..15}
04 05 06 07 08 09 10 11 12 13 14 15
$
$ echo {004..010}
004 005 006 007 008 009 010
$
$ echo {04..-7}
04 03 02 01 00 -1 -2 -3 -4 -5 -6 -7
$
$ echo {04..-07}
004 003 002 001 000 -01 -02 -03 -04 -05 -06 -07
$

De manire facultative, un troisime nombre pas peut fixer le pas dincrmentation ou de


dcrmentation.

Ex : $ echo {-4..7..3}
-4 -1 2 5
$

Combins avec le mcanisme de gnration de chanes [cf. Chapitre 9, Chanes de caractres 8],
les intervalles dentiers sont utiliss pour crer rapidement des noms de fichiers numrots.

Ex : $ touch fich{0..4}
$
$ ls
fich0 fich1 fich2 fich3 fich4
$

Lexemple ci-dessous utilise un intervalle dentiers et une itration for pour afficher les dix chiffres.

Ex : $ for i in {0..9}
> do

103
> echo $i
> done
0
1
2
3
4
5
6
7
8
9
$

Remarque : le paramtrage des bornes dun intervalle dentiers ne peut seffectuer directement
car les substitutions ne sont pas interprtes lintrieur des accolades.

Ex : $ a=1 b=5
$
$ echo {$a..$b}
{1..5}
$

Pour que linterprtation soit excute, on peut utiliser la commande interne eval.
Cela permet, par exemple, de construire une itration paramtre.

Ex : $ eval echo {$a..$b}


1 2 3 4 5
$
$ for i in $( eval echo {$a..$b} )
> do
> echo $i
> done
1
2
3
4
5
$

4. Commande interne ((
Cette commande interne est utilise pour effectuer des oprations arithmtiques.

Syntaxe : (( expr_arith ))

Son fonctionnement est le suivant : expr_arith est value ; si cette valuation donne une valeur
diffrente de 0, alors le code de retour de la commande interne (( est gal 0 sinon le code de
retour est gal 1.
Il est donc important de distinguer deux aspects de la commande interne (( expr_arith )) :
- la valeur de expr_arith issue de son valuation et
- le code de retour de (( expr_arith )).

Attention : la valeur de expr_arith n'est pas affiche sur la sortie standard.

104
Ex : $ (( -5 )) => la valeur de l'expression arithmtique est gale -5 (c.--d.
$ => diffrente de 0), donc le code de retour de (( est gal 0
$ echo $?
0
$
$ (( 0 )) => la valeur de l'expression arithmtique est 0, donc le code de retour
$ => de (( est gal 1
$ echo $?
1
$

Les oprateurs permettant de construire des expressions arithmtiques valuables par bash sont
issus du langage C (ex : = + - > <=).

Ex : $ declare -i a=2 b
$ (( b = a + 7 ))
$

Le format d'criture est libre l'intrieur de la commande ((. En particulier, plusieurs caractres
espace ou tabulation peuvent sparer les deux membres d'une affectation.

Il est inutile d'utiliser le caractre de substitution $ devant le nom d'une variable car il n'y a pas
d'ambigut dans l'interprtation ; par contre, lorsqu'une expression contient des paramtres de
position, le caractre $ doit tre utilis.

Ex : $ date
jeudi 10 avril 2014, 17:39:55 (UTC+0200)
$
$ set $(date)
$
$ (( b = $2 +1 )) => incrmentation du jour courant
$
$ echo $b
11
$

Code de retour de (( et structures de contrle :

Le code de retour d'une commande interne (( est souvent exploit dans une structure de contrle if
ou while.

Le programme shell dix ci-dessous affiche les dix chiffres :


#!/bin/bash

declare -i i=0

while (( i < 10 ))
do
echo $i
(( i = i + 1 )) # ou (( i++ ))
done

Son fonctionnement est le suivant : lexpression i < 10 est value, sa valeur est vraie, le code de
retour de (( i < 10 )) est gal 0, le corps de litration est excut. Aprs affichage de la valeur 9,
la valeur de i devient gale 10. Lexpression i < 10 est value, sa valeur est maintenant fausse, le
code de retour de (( i < 10 )) est gal 1, litration se termine.

105
Ex : $ dix
0
1
2
3
4
5
6
7
8
9
$

5. Valeur d'une expression arithmtique


La commande interne (( expr_arith )) n'affiche pas sur la sortie standard la valeur de l'expression
arithmtique expr_arith.

Pour obtenir la valeur de l'expression arithmtique, on utilise la syntaxe : $(( expr_arith ))

Ex : echo $(( 7 * 2 )) echo $(( a= 12*8 )) echo $(( 7 < 10 ))

Substitutions de commandes et substitutions de paramtres peuvent tre prsentes dans une


commande interne (( ou bien dans une substitution dexpression arithmtique $(( )) si le rsultat
aboutit un nombre entier.
Par exemple, dans lexpression $(( $(ls -l | wc -l) -1 )) le rsultat du pipeline ls -l |
wc l peut tre interprt comme un nombre.

Attention : lors de l'valuation d'une expression arithmtique, les dbordements ventuels ne


sont pas dtects.

Ex : $ echo $((897655*785409*56789*6789999999999999999999 ))
-848393034087410691 => nombre ngatif !
$

Si lon souhaite utiliser de grands entiers (ou des nombres rels), il est prfrable dutiliser
la commande unix bc.

Ex : $ bc q
897655*785409*56789*6789999999999999999999
271856250888322242449959962260546638845
quit => pour sortir de bc
$

Loption q de bc vite laffichage du message de bienvenue lorsquon utilise cette


commande de manire interactive.

Base sur le contexte, linterprtation des expressions arithmtiques est particulirement souple en
bash.

Ex : $ declare -i x=35
$
$ z=x+5 => affectation de la chane x+5 la variable z

106
$ echo $z
x+5 => non value car z de type chane de caractres par dfaut
$
$ echo $((z)) => par le contexte, z est value comme une variable de type entier
40
$ (( z = z+1))
$ echo $z
41
$

6. Oprateurs
Une expression arithmtique contenue dans une commande interne (( peut tre une valeur, un
paramtre ou bien tre construite avec un ou plusieurs oprateurs. Ces derniers proviennent du
langage C. La syntaxe des oprateurs, leur signification, leur ordre de priorit et les rgles
d'associativit sinspirent du langage C.

Les oprateurs traits par la commande (( sont mentionns ci-dessous, munis de leur associativit (g
: de gauche droite, d : de droite gauche). Les oprateurs ayant mme priorit sont regroups dans
une mme classe et les diffrentes classes sont cites par ordre de priorit dcroissante.

(1) a++ a-- post-incrmentation, post-dcrmentation (g)

(2) ++a --a pr-incrmentation, pr-dcrmentation (d)

(3) -a +a moins unaire, plus unaire (d)

(4) !a ~a ngation logique, ngation binaire (d)

(5) a**b exponentiation : ab (d)

(6) a*b a/b a%b multiplication, division entire, reste (g)

(7) a+b a-b addition, soustraction (g)

(8) a<<n a>>n dcalage binaire gauche, droite (g)

(9) a<b a<=b a>b a>=b comparaisons (g)

(10) a==b a!=b galit, diffrence (g)

(11) a&b ET binaire (g)

(12) a^b OU EXCLUSIF binaire (g)

(13) a|b OU binaire (g)

(14) a&&b ET logique (g)

(15) a||b OU logique (g)

(16) a?b:c oprateur conditionnel (d)

107
(17) a=b a*=b a%=b oprateurs d'affectation (d)
a/=b a+=b a-=b
a&=b a^=b a|=b
a<<=n a>>=n

(18) a,b oprateur virgule (g)

Ces oprateurs se dcomposent en :


- oprateurs arithmtiques
- oprateurs relationnels
- oprateurs logiques
- oprateurs binaires
- oprateurs d'affectation
- oprateurs divers.

Oprateurs arithmtiques :

Les quatre oprateurs ci-dessous sappliquent une variable.

Post-incrmentation : var++ la valeur de var est dabord utilise, puis est incrmente

Ex : $ declare -i x=9 y
$ (( y = x++ )) => y reoit la valeur 9 ; x vaut 10
$ echo "y=$y x=$x"
y=9 x=10
$

Post-dcrmentation : var-- la valeur de var est dabord utilise, puis est dcrmente

Ex : $ declare -i x=9 y
$ (( y = x-- )) => y reoit la valeur 9 ; x vaut 8
$ echo "y=$y x=$x"
y=9 x=8
$

Pr-incrmentation : ++var la valeur de var est dabord incrmente, puis est utilise

Ex : $ declare -i x=9 y
$ (( y=++x)) => x vaut 10 ; y reoit la valeur 10
$ echo "y=$y x=$x"
y=10 x=10
$

Pr-dcrmentation : --var la valeur de var est dabord dcrmente, puis est utilise

Ex : $ declare -i x=9 y
$ (( y= --x )) => x vaut 8 ; y reoit la valeur 8
$ echo "y=$y x=$x"
y=8 x=8
$

108
Les autres oprateurs sappliquent des expressions arithmtiques.

Plus unaire : + expr_arith


Moins unaire : - expr_arith
Addition : expr_arith + expr_arith
Soustraction : expr_arith - expr_arith
Multiplication : expr_arith * expr_arith
Division entire : expr_arith / expr_arith
Reste de division entire : expr_arith % expr_arith

Ex : $ declare i b=8 c=2


$ (( a = b/3 +c )) => division entire et addition
$
$ echo $(( RANDOM%49 + 1 )) => reste et addition
23
$

La variable prdfinie du shell RANDOM renvoie une valeur pseudo-alatoire ds qu'elle est
utilise.

L'utilisation de parenthses permet de modifier l'ordre d'valuation des composantes d'une


expression arithmtique.

Ex : $ (( a = ( b+c )*2 ))
$

Oprateurs relationnels :

Lorsqu'une expression relationnelle (ex : a < 3) est vraie, la valeur de l'expression est gale 1.
Lorsqu'elle est fausse, sa valeur est gale 0.

Egalit : expr_arith == expr_arith (Attention aux deux caractres gal)


Diffrence : expr_arith != expr_arith
Infrieur ou gal : expr_arith <= expr_arith
Suprieur ou gal : expr_arith >= expr_arith
Strictement infrieur : expr_arith < expr_arith
Strictement suprieur : expr_arith > expr_arith

Ex : $ declare i a=4
$
$ (( a<3 )) => expression fausse, valeur gale 0, code de retour gal 1
$ echo $?
1
$

Ex : $ declare i a=3 b=2


$
$ if (( a == 7 ))
> then (( a= 2*b ))
> else (( a = 7*b))
> fi
$
$ echo $a
14
$

109
L'expression relationnelle a == 7 est fausse, sa valeur est 0 et le code de retour de (( a == 7 )) est
gal 1 : c'est donc la partie else qui est excute.

Oprateurs logiques :

Comme pour une expression relationnelle, lorsqu'une expression logique (ex : a > 3 && a < 5) est
vraie, la valeur de l'expression est gale 1.
Lorsqu'elle est fausse, sa valeur est gale 0.

Ngation logique : ! expr_arith

Si la valeur de expr_arith est diffrente de 0, la valeur de ! expr_arith est gale 0.


Si la valeur de expr_arith est gale 0, la valeur de ! expr_arith est gale 1.
Au moins un caractre espace doit tre prsent entre ! et expr_arith.

Ex : $ echo $(( ! 12 )) => echo $(( !12 )) provoque une erreur


0
$

Et logique : expr_arith1 && expr_arith2

Si la valeur de expr_arith1 est gale 0 (fausse), alors expr_arith2 n'est pas value et la
valeur de expr_arith1 && expr_arith2 est 0.
Si la valeur de expr_arith1 est diffrente de 0 (vraie), alors expr_arith2 est value : si sa
valeur est gale 0, alors la valeur de expr_arith1 && expr_arith2 est 0, sinon elle vaut
1.

Ex: $ declare i a=4


$
$ echo $(( a<3 )) => expression fausse
0
$
$ echo $(( a > 3 && a <5 )) => expression vraie, valeur gale 1
1
$ ((a>3 && a<5 )) => expression vraie, code de retour gal 0
$ echo $?
0
$

Ou logique : expr_arith1 || expr_arith2

Si la valeur de expr_arith1 est diffrente de 0 (vraie), alors expr_arith2 n'est pas


value et la valeur de expr_arith1 || expr_arith2 est gale 1.
Si la valeur de expr_arith1 est gale 0 (fausse), alors expr_arith2 est value : si sa valeur
est diffrente de 0, alors la valeur de expr_arith1 || expr_arith2 est 1, sinon elle vaut 0.

Ex : $ declare i x=4
$
$ (( x > 4 || x < 4 ))
$ echo $?
1
$
$ echo $(( x > 4 || x<4 ))
0
$

110
Oprateurs binaires :

Ngation binaire : ~ expr_arith


Dcalage binaire gauche : expr_arith <<nb_bits
Dcalage binaire droite : expr_arith >>nb_bits
Et binaire : expr_arith & expr_arith
Ou exclusif binaire (xor) : expr_arith ^ expr_arith
Ou binaire : expr_arith | expr_arith

Ces oprateurs sont utiliss pour manipuler la valeur dentiers via leur reprsentation binaire.

Ex : $ declare -i a=2#1000011110100100
$
$ printf "%d\n" $a
34724
$
$ printf "%0x\n" $a
87a4
$
$ declare -i b=$(( a & 0xf )) => les 4 bits de droite de a sont copis dans b
$
$ printf "%d\n" $b
4 => b : 2#0100
$
$ (( b = b | 2#1 )) => le bit de droite de b est mis 1
$ printf "%d\n" $b
5 => b : 2#0101
$

Oprateurs d'affectations :

Affectation simple : nom = expr_arith


Affectation compose : nom oprateur= expr_arith

Comme en langage C, l'affectation n'est pas une instruction (on dirait commande dans la
terminologie du shell) mais une expression, et comme toute expression elle possde une valeur.
Celle-ci est la valeur de son membre gauche aprs valuation de son membre droit.

Dans lexemple ci-dessous, la valeur 5 est pralablement affecte la variable c : la valeur de


lexpression c=5 est par consquent gale 5, puis cette valeur est affecte la variable b, etc.

Ex : $ ((a=b=c=5)) => la valeur de lexpression a=b=c=5 est gale 5


$ echo $a $b $c
5 5 5
$

Dans l'exemple ci-dessous, l'expression a = b + 5 est value de la manire suivante : b est


value (sa valeur est 2), puis c'est l'expression b+5 qui est value (sa valeur vaut 7), enfin cette
valeur est affecte la variable a. La valeur de l'expression a = b + 5 est gale celle de a, c'est
dire 7.

Ex : $ declare i b=2

111
$
$ echo $(( a = b+5 ))
7
$
$ echo $a
7
$

La syntaxe nom oprateur= expr_arith est un raccourci d'criture provenant du langage C et


signifiant :
nom = nom oprateur expr_arith

oprateur pourra tre : * / % + - << >> & ^ |

Ex : $ (( a += 1 )) => ceci est quivalent (( a = a + 1 ))


$

Oprateurs divers :

Exponentiation : expr_arith1 ** expr_arith2

Contrairement aux autres oprateurs, loprateur dexponentiation ** nest pas issu du


langage C. Son associativit est de droite gauche (d).

Ex : $ echo $(( 2**3**2 ) => interprte comme 2**(3**2) : 29


512
$

Oprateur conditionnel : expr_arith1 ? expr_arith2 : expr_arith3

Le fonctionnement de cet oprateur ternaire est le suivant : expr_arith1 est value, si sa


valeur est vraie la valeur de l'expression arithmtique est celle de expr_arith2, sinon c'est
celle de expr_arith3.

Ex : $ declare -i a=4 b=0


$ echo $(( a < 3 ? (b=5) : (b=54) ))
54
$
$ echo $b
54
$

Il aurait galement t possible dcrire : (( b = a < 3 ? 5 : 54 ))

Oprateur virgule : expr_arith1 , expr_arith2

expr_arith1 est value, puis expr_arith2 est value ; la valeur de lexpression est celle de
expr_arith2.

Ex : $ declare -i a b
$ echo $(( a=4,b=9 ))
9
$ echo "a=$a b=$b"
a=4 b=9
$

112
7. Structure for pour les expressions arithmtiques
Bash a introduit une nouvelle structure for adapte aux traitements des expressions arithmtiques,
itration issue du langage C. Elle fonctionne comme cette dernire.

Syntaxe : for (( expr_arith1 ; expr_arith2 ; expr_arith3 ))


do
suite_cmd
done

expr_arith1 est l'expression arithmtique d'initialisation.


expr_arith2 est la condition darrt de litration.
expr_arith3 est lexpression arithmtique qui fixe le pas dincrmentation ou de dcrmentation.

Exemples : declare -i x # affiche les dix chiffres


for (( x=0 ; x<10 ; x++ ))
do
echo $x
done

declare -i x y
for (( x=1,y=10 ; x<4 ; x++,y-- ))
do
echo $(( x*y ))
done

Exercice 3 : En utilisant RANDOM, crire un programme tirage_flash qui affiche cinq entiers
diffrents compris entre 1 et 49 et un nombre compris entre 1 et 10.

Exercice 4 : Ecrire un programme factiter qui prend un entier N positif ou nul en argument et
affiche sa factorielle N!
Attention aux dbordements : N ne doit pas tre trop grand.

Ex : $ factiter 7
5040
$
$ factiter 0
1
$

Exercice 5 : Ecrire une version rcursive factrecur du programme prcdent.

8. Exemple : les tours de Hanoi


Le problme des tours de Hano peut snoncer de la manire suivante :
- conditions de dpart : plusieurs disques sont placs sur une table A, les uns sur les autres,
rangs par taille dcroissante, le plus petit tant au dessus de la pile

113
- rsultat attendu : dplacer cette pile de disques de la table A vers une table B
- rgles de fonctionnement :
. on dispose d'une troisime table C,
. on ne peut dplacer qu'un disque la fois, celui qui est plac en haut d'une pile et le
dposer uniquement sur un disque plus grand que lui ou bien sur une table vide.

Le programme shell rcursif hanoi traite ce problme ; il utilise quatre arguments : le nombre de
disques et le nom de trois tables.
#!/bin/bash

if (( $1 > 0 ))
then
hanoi $(( $1 - 1)) $2 $4 $3
echo Deplacer le disque de la table $2 a la table $3
hanoi $(( $1 - 1)) $4 $3 $2
fi

Pour excuter ce programme, on indique le nombre total N de disques prsents sur la premire table,
le nom de la table o sont placs ces N disques et le nom des deux autres tables.
Dans l'exemple mentionn, la table A contient au dpart trois disques et les deux autres tables B et C
sont vides. Le programme affiche chaque dplacement effectu.

Ex : $ hanoi 3 A B C
Deplacer le disque de la table A a la table B
Deplacer le disque de la table A a la table C
Deplacer le disque de la table B a la table C
Deplacer le disque de la table A a la table B
Deplacer le disque de la table C a la table A
Deplacer le disque de la table C a la table B
Deplacer le disque de la table A a la table B
$

114
Chapitre 12 : Tableaux

Moins utiliss que les chanes de caractres ou les entiers, bash intgre les tableaux classiques et
les tableaux associatifs. Les lments des premiers sont indics par des entiers, tandis que les
lments des seconds sont indexs par des chanes de caractres.
Les tableaux classiques et associatifs sont monodimensionnels.

1. Tableaux classiques
1.1 Dfinition et initialisation

Pour crer un ou plusieurs tableaux classiques vides, on utilise gnralement l'option -a de la


commande interne declare :

declare -a nomtab ...

Le tableau nomtab est simplement cr mais ne contient aucune valeur : le tableau est dfini mais
n'est pas initialis.

Pour lister les tableaux classiques dfinis : declare -a

Ex : $ declare -a
declare -a BASH_ARGC='()'
declare -a BASH_ARGV='()'
declare -a BASH_LINENO='()'
declare -a BASH_SOURCE='()'
declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="24" [3]="1"
[4]="release" [5]="i686-pc-linux-gnu")'
declare -a DIRSTACK='()'
declare -a FUNCNAME='()'
declare -a GROUPS='()'
declare -a PIPESTATUS='([0]="0")'
$

Pour dsigner un lment d'un tableau classique, on utilise la syntaxe : nomtab[indice]

Ex : $ declare -a tab => dfinition du tableau tab


$
$ read tab[1] tab[3]
coucou bonjour
$
$ tab[0]=hello
$

Pour dfinir et initialiser un tableau classique : declare -a nomtab=( val0 val1 ... )

Comme en langage C, l'indice d'un tableau classique dbute toujours 0 et sa valeur maximale est
celle du plus grand entier positif reprsentable dans ce langage (bash a t crit en C). L'indice
peut tre une expression arithmtique.

115
Il n'est pas obligatoire dutiliser la commande interne declare pour crer un tableau classique, il
suffit d'initialiser un de ses lments :

Ex : $ array[3]=bonsoir => cration du tableau array avec


$ => initialisation de llment dindice 3

Trois autres syntaxes sont galement utilisables pour initialiser globalement un tableau classique :

- nomtab=( val0 val1 ... )

- nomtab=( [indice]=val ... )

Ex : $ arr=([1]=coucou [3]=hello)
$

- l'option -a de la commande interne read ou readonly. Chaque mot saisi devient un


lment du tableau classique :

Ex : $ read -a tabmess
bonjour tout le monde
$

Pour crer un tableau classique en lecture seule, on utilise les options ra.

Ex : $ declare -ra tabconst=( bonjour coucou salut ) => tableau en lecture seule
$
$ tabconst[1]=ciao
bash: tabconst : variable en lecture seule
$

Pour afficher les valeurs et attributs dun tableau classique, on utilise la syntaxe :
declare p tab

Ex : $ declare -p tabconst
declare -ar tabconst='([0]="bonjour" [1]="coucou" [2]="salut")'
$

1.2 Oprations sur un lment de tableau classique

Valeur d'un lment

On obtient la valeur d'un lment d'un tableau classique laide de la syntaxe :


${nomtab[indice]}

Bash calcule d'abord la valeur de l'indice puis l'lment du tableau est remplac par sa valeur.
Il est possible d'utiliser :

- toute expression arithmtique valide de la commande interne (( pour calculer l'indice d'un
lment

Ex : $ echo ${tabmess[1]}
tout
$

116
$ echo ${tabmess[RANDOM%4]} => ou bien : ${tabmess[$((RANDOM%4))]}
monde
$
$ echo ${tabmess[1**2+1]}
le
$

- une variable contenant un entier

Ex : $ a=3
$ echo ${tabmess[a]}
monde
$

Exercice 1 : Ecrire un programme shell carte qui affiche le nom d'une carte tire au hasard d'un
jeu de 32 cartes. On utilisera deux tableaux : un tableau couleur et un tableau
valeur.

Ex : $ carte
huit de carreau
$ carte
as de pique
$

Lorsqu'un nom de tableau est prsent sans indice dans une chane de caractres ou une expression,
bash linterprte comme lment d'indice 0.

Ex : $ echo $tabmess
bonjour
$

Rciproquement, une variable non pralablement dfinie comme tableau peut tre interprte
comme un tableau classique.

Ex : $ var=bonjour
$ echo ${var[0]} => var est interprte comme un tableau un seul lment
bonjour => dindice 0
$ var=( coucou "${var[0]}" )
$ echo ${var[1]} => var est devenu un vritable tableau
bonjour
$

Longueur d'un lment

Pour obtenir la longueur d'un lment d'un tableau classique : ${#nomtab[indice]}

Ex : $ echo ${tabmess[0]}
bonjour
$
$ echo ${#tabmess[0]}
7 => longueur de la chane bonjour
$

117
Suppression dun lment

Suppression d'un ou plusieurs lments d'un tableau classique : unset nomtab[indice] ...

Autres oprations

Les diffrents traitements sur les chanes de caractres vus prcdemment [cf. Chapitre 9,
Chanes de caractres 3, 4, 5, 6] sont galement applicables aux lments dun tableau
classique.

Suppression dune sous-chane :


${nomtab[indice]#modle} ${nomtab[indice]##modle}
${nomtab[indice]%modle} ${nomtab[indice]%%modle}

Extraction dune sous-chane :


${nomtab[indice]:ind} ${nomtab[indice]:ind:nb}

Substitution de sous-chanes :
${nomtab[indice]/mod/ch} ${nomtab[indice]//mod/ch}

Transformation majuscules/minuscules :
${nomtab[indice]^^} ${nomtab[indice],,}

Ex : $ tpers=("Jean Fontaine:20:1,72" "Pierre Cascade:18:1,83")


$
$ echo ${tpers[1]#*:}
18:1,83
$
$ echo ${tpers[0]^^}
JEAN FONTAINE:20:1,72
$

1.3 Oprations sur un tableau classique

Nombre dlments dun tableau classique : ${#nomtab[@]}

Parmi les diffrentes notations possibles pour connatre le nombre dlments dun tableau
classique, on utilisera celle-ci : ${#nomtab[@]}

Il est noter que seuls les lments initialiss sont compts.

Ex : $ arr=([1]=coucou [3]=hello)
$ echo ${#arr[@]}
2
$

Accs tous les lments dun tableau classique : "${nomtab[@]}"

Comme pour "$@" et "$*" [cf. Chapitre 2, Substitution de paramtres 2.5], les syntaxes
"${nomtab[*]}" et "${nomtab[@]}" nont pas la mme signification pour le shell :
- "${nomtab[*]}" sera remplace par lensemble des lments du tableau classique
nomtab, concatns en une seule chane et spars par le premier caractre de IFS :

118
"val0 val1 ... "
- "${nomtab[@]}" sera remplace par autant de chanes quil y a dlments :
"val0" "val1" ...

Ex : $ tabPays=("Etats Unis" France)


$
$ set "${tabPays[*]}"
$ echo $#
1 => une seule chane
$
$ echo $1
Etats Unis France
$
$ set "${tabPays[@]}"
$ echo $#
2 => deux chanes
$
$ echo $1
Etats Unis
$ echo $2
France
$

Lorsque les lments sont de simples chanes constitues dun seul mot, il ny a aucune difficult
pour prserver lintgrit de celles-ci. Cela est diffrent avec des chanes composes.

Ex : $ for p in ${tabPays[*]}
> do
> echo $p
> done
Etats => lintgrit du premier lment est rompue
Unis
France
$

Pour prserver lintgrit de chaque lment, il est prfrable dutiliser la syntaxe :


"${nomtab[@]}".

Ex : $ for p in "${tabPays[@]}"
> do
> echo $p
> done
Etats Unis => lintgrit du premier lment est prserve
France
$

Liste de tous les indices dfinis : "${!nomtab[@]}"

Il existe galement plusieurs syntaxes pour obtenir la liste de tous les indices conduisant un
lment dfini dun tableau classique. Afin dutiliser une syntaxe commune avec les tableaux
associatifs, on utilisera la notation : "${!nomtab[@]}"

Ex : $ arr=([1]=coucou bonjour [5]=hello)


$
$ echo "${!arr[@]}"
1 2 5 => pour affecter un indice bonjour, bash a incrment lindice

119
$ => de llment prcdent

Lintrt dutiliser cette syntaxe est quelle permet de ne traiter que les lments dfinis dun
tableau trous .

Ex : $ for i in "${!arr[@]}"
> do
> echo "$i => ${arr[i]}" => dans lexpression ${arr[i]}, bash interprte
> done => directement i comme un entier
1 => coucou
2 => bonjour
5 => hello
$

Copie dun tableau classique

Pour copier un tableau classique tab : tabcopie=( "${tab[@]}" )

Ex : $ tabcopy=( "${tabPays[@]}" )
$
$ echo "${tabcopy[@]}"
Etats Unis France
$

Ajout dlments un tableau classique

Pour ajouter un ou plusieurs lments un tableau classique tab :


- la fin : tab+=( val1 val2 )
- en tte : tab=( val0 val1 "${tab[@]}")

Ex : $ tab=("un 1" "deux 2" "trois 3")


$
$ tab+=("quatre 4" fin) => ajout de plusieurs lments en fin de tableau
$
$ echo "${tab[@]}"
un 1 deux 2 trois 3 quatre 4 fin
$
$ tab=(debut "zero 0" "${tab[@]}") => ajout de plusieurs lments en
$ => tte de tableau
$ echo ${#tab[@]}
7 => nombre dlments du tableau
$ echo "${tab[@]}"
debut zero 0 un 1 deux 2 trois 3 quatre 4 fin
$
$ echo ${tab[5]}
quatre 4
$

Suppression dun tableau classique

Pour supprimer un ou plusieurs tableaux classiques : unset nomtab ...

Ex : $ unset tabcopy tab


$

120
Exercice 2 : Ecrire un programme shell distrib qui cre un paquet de 5 cartes diffrentes tires
au hasard parmi un jeu de 32 cartes et affiche le contenu du paquet.

Exercice 3 : Ecrire un programme shell tabnoms qui place dans un tableau les noms de tous les
utilisateurs enregistrs dans le fichier /etc/passwd, affiche le nombre total
d'utilisateurs enregistrs, puis tire au hasard un nom d'utilisateur.

2. Tableaux associatifs

2.1 Dfinition et initialisation

Dans un tableau associatif, les index permettant daccder aux lments du tableau ne sont plus
des entiers positifs ou nuls mais des chanes de caractres appeles cls.

Pour crer un ou plusieurs tableaux associatifs vides, on utilise la syntaxe :


declare -A nomtabA ...

Pour dfinir et initialiser un tableau associatif, il est possible dutiliser les syntaxes suivantes :
declare -A nomtabA=( [cl]=val ... )
ou bien
declare -A nomtabA
nomtabA=( [cl]=val ... )

Contrairement aux tableaux classiques, lutilisation de la syntaxe declare -A est imprative pour
crer un tableau associatif.

Ex : $ declare -A tabCapA=( [fr]=Paris [it]=Rome )


$
$ declare -A tabMonA
$ tabMonA=( [France]=euro ["Etats Unis"]="dollar US" )
$

Pour lister les tableaux associatifs dfinis : declare -A

Ex : $ declare -A
declare -A BASH_ALIASES='()'
declare -A BASH_CMDS='()'
declare -A tabCapA='([fr]="Paris" [it]="Rome" )'
declare -A tabMonA='([France]="euro" ["Etats Unis"]="dollar US" )'
$

Pour dsigner un lment d'un tableau associatif : nomtabA[cl]

Ex : $ declare -A tailleA
$ read tailleA[Pierre] tailleA[Jean]
1,83 1,72
$

121
Pour crer un tableau associatif en lecture seule, on utilise les options rA :

Ex : $ declare -rA tconstA=( [Aline]=22 [Marie]=43 ) => tableau en lecture seule


$
$ tconstA[Aline]=23 => modification dune valeur
bash: tconstA : variable en lecture seule
$
$ tconstA[Julie]=34 => ajout dun lment
bash: tconstA : variable en lecture seule
$

Pour afficher les valeurs et attributs dun tableau associatif, on utilise la syntaxe usuelle :
declare p nomtabA

Ex : $ declare p tailleA
declare -A tailleA='([Jean]="1,72" [Pierre]="1,83" )'
$

2.2 Oprations sur un lment de tableau associatif

Valeur d'un lment

Pour obtenir la valeur d'un lment d'un tableau associatif, on utilise la syntaxe :
${nomtabA[cl]}

Ex : $ echo ${tailleA[Jean]}
1,72
$

Longueur d'un lment

Pour obtenir la longueur d'un lment d'un tableau associatif : ${#nomtabA[cl]}

Ex : $ echo ${#tailleA[Pierre]}
4 => longueur de la chane 1,83
$

Suppression dun lment

Suppression d'un ou plusieurs lments d'un tableau associatif : unset nomtabA[cl] ...

Autres oprations

Les traitements sur les lments dun tableau classique sont galement applicables aux lments
dun tableau associatif.

Ex : $ declare -A tPaysA=([France]="Paris:euro:fr" ["Etats Unis"]="Washington,


D.C.:dollar US:us")
$
$ echo ${tPaysA["Etats Unis"]/dollar US/USD}
Washington, D.C.:USD:us
$

122
2.3 Oprations sur un tableau associatf

Nombre dlments dun tableau associatif : ${#nomtabA[@]}

Pour obtenir le nombre d'lments du tableau associatif nomtabA, on utilisera la mme


syntaxe que pour les tableaux classiques : ${#nomtabA[@]}

Ex : $ declare -A tabPersA=([Pierre]="Canson Bonnefoy:1,73:20" ["Jean Michel


"]="Dupont:1,72:18")
$
$ echo ${#tabPersA[@]}
2
$

Accs tous les lments dun tableau associatif : "${nomtabA[@]}"

Pour lister toutes les valeurs dun tableau associatif, on utilise la mme syntaxe que pour les
tableaux classiques : "${nomtabA[@]}"

Ex : $ for p in "${tabPersA[@]}"
> do
> echo $p
> done
Canson Bonnefoy:1,73:20 => lintgrit de la valeur de llment est prserve
Dupont:1,72:18
$

Liste de toutes les cls dfinies : "${!nomtab[@]}"

Il est dconseill dutiliser la syntaxe ${!nomtabA[@]} pour lister toutes les cls dun tableau
associatif, car les lments sont accds via des cls qui sont elles mme des chanes de caractres
pouvant tre composes de plusieurs mots.

Ex : $ for cl in ${!tabPersA[@]}
> do
> echo "$cl => ${tabPersA[$cl]}"
> done
Pierre => Canson Bonnefoy:1,73:20
Jean => => lintgrit de la cl na pas t prserve
Michel =>
$

Par consquent, pour lister toutes les cls dun tableau associatif, on prfrera utiliser la syntaxe :
"${!nomtab[@]}"

Ex : $ for cl in "${!tabPersA[@]}"
> do
> echo "$cl => ${tabPersA[$cl]}"
> done
Pierre => Canson Bonnefoy:1,73:20
Jean Michel => Dupont:1,72:18 => lintgrit de la cl est prserve
$

Remarque : contrairement aux tableaux classiques, la syntaxe ${tabPersA[cl]} ne peut tre


utilise pour un tableau associatif car cl est une chane de caractres. Seule la

123
notation ${tabPersA[$cl]} doit tre employe.

Ajout dlments un tableau associatif

Les notions de dbut ou de fin dun tableau associatif ne sont pas pertinentes. De mme, il ne peut
y avoir de trous dans un tableau associatif : aucune relation dordre nest dfinie sur les
lments dun tableau associatif.

Pour ajouter un ou plusieurs lments un tableau associatif tabA, on peut utiliser la syntaxe :
tabA+=( [cl]=val )

Ex : $ declare -A tabCapA=( [fr]=Paris [it]=Rome )


$
$ tabCapA+=( [es]=Madrid [de]=Berlin)
$

Copie dun tableau associatif

Pour copier un tableau associatif tabA dans un autre cpA, la mthode la plus simple consiste
copier itrativement lment par lment.

Ex : $ declare -A tabA=( [jean louis]="dupond latour" [yves andre michel]="de


la rosette")
$
$ declare -A cpA => cration du nouveau tableau associatif cpA
$ for cl in "${!tabA[@]}"
> do
> cpA+=( [$cl]="${tabA[$cl]}" ) => ajout dans le nouveau tableau
> done
$
$ declare -p tabA cpA => affichage
declare -A tabA='(["jean louis"]="dupond latour" ["yves andre
michel"]="de la rosette" )'
declare -A cpA='(["jean louis"]="dupond latour" ["yves andre michel"]="de
la rosette" )'
$

Suppression dun tableau associatif

Pour supprimer un ou plusieurs tableaux associatifs : unset nomtabA ...

Exercice 4 : Ecrire un programme shell tabnomsA qui cre partir du fichier /etc/passwd un
tableau associatif de la manire suivante :
- le nom dutilisateur est utilis comme cl du tableau associatif
- le restant de la ligne constitue la valeur de llment. On omettra toutefois
dinclure dans cette valeur, le champ correspondant au mot de passe :x:.

Par exemple, la ligne du fichier /etc/passwd :


sanchis:x:1000:1000:eric sanchis,,,:/home/sanchis:/bin/bash
devient :
tabnomA[sanchis]=1000:1000:eric sanchis,,,:/home/sanchis:/bin/bash

124
Chapitre 13 : Alias

Un alias permet d'abrger une longue commande, de remplacer le nom dune commande
existante par un autre nom ou bien de modifier le comportement dune commande existante.
De manire plus gnrale, un alias est utilis pour remplacer une longue chane de caractres
par une chane plus courte.

Pour connatre lensemble des alias dfinis, on utilise la commande alias sans argument.

Ex : $ alias
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo
terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-
9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
$

Pour connatre la valeur dun ou plusieurs alias : alias nom

Ex : $ alias ll
alias ll='ls -alF'
$

1. Cration dun alias


Pour crer un ou plusieurs alias, on utilise la syntaxe : alias nom=valeur ...

Ex : $ alias cx=chmod u+x


$

Le nom de lalias peut tre prsent dans sa propre dfinition. La commande alias rm='rm -i'
redfinit le comportement par dfaut de la commande unix rm en demandant lutilisateur de
confirmer la suppression (on force lutilisateur utiliser loption -i).

Ex : $ alias rm='rm -i'


$
$ > err => cration du fichier err
$
$ rm err
rm : supprimer fichier vide err ? o => lalias rm demande
$ => confirmation
$ ls err => le fichier err a t supprim
ls: impossible d'accder err: Aucun fichier ou dossier de ce type
$

125
Si lon souhaite temporairement obtenir le fonctionnement originel de la commande unix rm,
il suffit de placer le caractre \ devant lalias.

Ex : $ > err => cration du fichier err


$
$ \rm err => fonctionnement standard de rm
$
$ ls err
ls: impossible d'accder err: Aucun fichier ou dossier de ce type
$

Attention :

On ne doit pas dfinir un alias et utiliser cet alias dans la mme ligne mais sur deux
lignes diffrentes.

Ex : $ alias aff='echo bonjour' ; aff tout le monde


Commande aff non trouve, vouliez-vous dire :
La commande apf issue du paquet apf-firewall (universe)
La commande caff issue du paquet signing-party (universe)
La commande aft issue du paquet aft (universe)
aff : commande introuvable => aff tout le monde na pu sexcuter !
$
$ aff la compagnie
bonjour la compagnie => lalias est connu
$

Si l'on dsire utiliser plusieurs alias dans la mme commande, il est ncessaire de laisser un
caractre espace ou tabulation comme dernier caractre de valeur.

Ex : $ cat /etc/debian_version
wheezy/sid
$
$ alias c=cat d=/etc/debian_version
$
$ c d
cat: d: Aucun fichier ou rpertoire de ce type
$

Dans lexemple ci-dessus, lalias d na pas t interprt car le dernier caractre de la valeur
de c nest ni un espace, ni une tabulation. En ajoutant un caractre espace, on obtient le
rsultat voulu.

Ex : $ alias c='cat '


$
$ c d
wheezy/sid
$

La valeur dun alias peut inclure plusieurs commandes.

126
Ex : $ pwd
/tmp => rpertoire courant
$ alias scd='echo salut ; cd ' => aprs cd il y a un caractre espace
$ alias rep=/home/sanchis/bin
$
$ scd rep
salut
$ pwd
/home/sanchis/bin => nouveau rpertoire courant
$

La protection de la valeur dun alias doit tre choisie judicieusement. Dfinissons un alias
affichant lheure courante. La suite de commandes excuter est la suivante :
set $(date) ; echo ${5%:*}
Cette suite de commandes peut tre entoure avec des caractres quote ou bien avec des
caractres guillemet.

Ex : $ date
lundi 24 fvrier 2014, 17:15:50 (UTC+0100)
$
$ alias h='set $(date) ; echo ${5%:*}'
$
$ h
17:19
$
$ sleep 60
... => attente de 60 secondes
$ h
17:20 => mise jour de lheure
$

Attention :

En entourant la suite de commandes avec des caractres guillemet, le shell excute les
substitutions avant daffecter la valeur lalias, puis interprte cet alias.

Ex : $ alias g="set $(date) ; echo ${5%:*}"


$
$ g
bash: Erreur de syntaxe prs du symbole inattendu (
$

Cest la prsence de la parenthse ouvrante de la chane de caractres :


set lundi 24 fvrier 2014, 17:15:50 (UTC+0100)
Cette chane est excute comme une commande par le shell, ce qui provoque lerreur.

2. Suppression dun alias


Pour rendre indfinie la valeur dun ou plusieurs alias, on utilise la commande interne
unalias.
La syntaxe est : unalias nom ...

127
Ex : $ unalias g alert rep aff scd
$
$ alias
alias c='cat '
alias cx='chmod u+x'
alias d='/etc/debian_version'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias h='set $(date) ; echo ${5%:*}'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
alias rm='rm -i'
$

3. Utilisation des alias


Mme sil est possible dutiliser des alias dans un fichier shell, il est conseill de ne les
utiliser quen session interactive. En effet, leur utilisation dans un programme shell prsente
peu dintrt :
- on ne peut leur fournir des arguments
- lorsquils sont utiliss comme raccourcis de commandes ou de chanes de caractres,
ils obscurcissent la lisibilit du code.

Dans un fichier shell, il est hautement prfrable dutiliser des fonctions plutt que des alias.

128
Chapitre 14 : Fonctions shell

1. Dfinition dune fonction

Pour dfinir une fonction, le shell bash propose plusieurs syntaxes telles que :

nom_fct() function nom_fct


{ ou bien {
suite_de_commandes suite_de_commandes
} }

Pour des raisons de lisibilit, nous utiliserons la deuxime forme.

nom_fct spcifie le nom de la fonction. Le corps de celle-ci est suite_de _commandes.

Pour appeler une fonction, il suffit de mentionner son nom.

Comme pour les autres commandes composes de bash, une fonction peut tre dfinie
directement partir dun shell interactif.

Ex : $ function f0
> {
> echo Bonjour tout le monde !
> }
$
$ f0 => appel de la fonction f0
Bonjour tout le monde !
$

Les mots rservs function et } doivent tre les premiers mots d'une commande pour quils
soient reconnus. Sinon, il suffit de placer un caractre point-virgule avant le mot-cl :

function nom
{ suite_de_commandes ;}

La dfinition dune fonction la C est galement possible :

function nom {
suite_de_commandes
}

L'excution d'une fonction s'effectue dans l'environnement courant, autorisant ainsi le partage
de variables.

Ex : $ c=Coucou
$
$ function f1
> {
> echo $c => utilisation dans la fonction dune variable externe c
> }

129
$
$ f1
Coucou
$

Les noms de toutes les fonctions dfinies peuvent tre lists l'aide de la commande :
declare -F

Ex : $ declare -F

declare -f f0
declare -f f1

$

Les noms et corps de toutes les fonctions dfinies sont affichs laide de la commande :
declare -f

Ex : $ declare -f

f0 ()
{
echo Bonjour tout le monde !
}
f1 ()
{
echo $c
}

$

Pour afficher le nom et corps dune ou plusieurs fonctions : declare -f nomfct ...

Ex : $ declare -f f0
f0 ()
{
echo Bonjour tout le monde !
}
$

Une dfinition de fonction peut se trouver en tout point dun programme shell ; il nest pas
obligatoire de dfinir toutes les fonctions en dbut de programme. Il est uniquement
ncessaire que la dfinition dune fonction soit faite avant son appel effectif, c'est--dire
avant son excution :

function f1
{ ... ;}

suite_commandes1

function f2
{ ... ;}

suite_commandes2

130
Dans le code ci-dessus, suite_commandes1 ne peut excuter la fonction f2 (contrairement
suite_commandes2). Cela est illustr par le programme shell appelAvantDef :

appelAvantDef
-----------------------------------
# !/bin/bash

echo Appel Avant definition de fct


fct # fct non definie

function fct
{
echo Execution de : fct
sleep 2
echo Fin Execution de : fct
}

echo Appel Apres definition de fct


fct # fct definie
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -

Son excution se droule de la manire suivante :

Ex : $ appelAvantDef
Appel Avant definition de fct
./appelAvantDef: line 4: fct : commande introuvable
Appel Apres definition de fct
Execution de : fct
Fin Execution de : fct
$

Lors du premier appel la fonction fct, celle-ci nest pas dfinie : une erreur dexcution se
produit. Puis, le shell lit la dfinition de la fonction fct : le deuxime appel seffectue
correctement.

Contrairement au programme prcdent, dans le programme shell pingpong, les deux


fonctions ping et pong sont dfinies avant leur appel effectif :

pingpong
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -
#!/bin/bash

function ping
{
echo ping
if (( i > 0 ))
then
((i--))
pong
fi
}

function pong
{
echo pong
if (( i > 0 ))
then
((i--))

131
ping
fi
}

declare -i i=4

ping # (1) ping et pong sont definies


- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -

Au point (1), les corps des fonctions ping et pong ont t lus par linterprteur de commandes
bash : ping et pong sont dfinies.

Ex : $ pingpong
ping
pong
ping
pong
ping
$

2. Suppression dune fonction

Une fonction est rendue indfinie par la commande : unset -f nomfct ...

Ex : $ declare -F

declare -f f0
declare -f f1

$
$ unset -f f1
$
$ declare -F

declare -f f0 => la fonction f1 nexiste plus !

$

3. Trace des appels aux fonctions

Le tableau prdfini FUNCNAME contient le nom des fonctions en cours dexcution,


matrialisant la pile des appels.

Le programme shell traceAppels affiche le contenu de ce tableau au dbut de son excution,


c'est--dire hors de toute fonction : le contenu du tableau FUNCNAME est vide (a). Puis la
fonction f1 est appele, FUNCNAME contient les noms f1 et main (b). La fonction f2 est
appele par f1 : les valeurs du tableau sont f2, f1 et main (c).

Lorsque lon est lintrieur dune fonction, la syntaxe $FUNCNAME (ou


${FUNCNAME[0]}) renvoie le nom de la fonction courante.

132
traceAppels
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -
#!/bin/bash

function f2
{
echo " ------ Dans f2 :"
echo " ------ FUNCNAME : $FUNCNAME"
echo " ------ tableau FUNCNAME[] : ${FUNCNAME[*]}" # (c)
}

function f1
{
echo " --- Dans f1 :"
echo " --- FUNCNAME : $FUNCNAME"
echo " --- tableau FUNCNAME[] : ${FUNCNAME[*]}" # (b)
echo " --- - Appel a f2 "
echo

f2
}

echo "Debut :"


echo "FUNCNAME : $FUNCNAME"
echo "tableau FUNCNAME[] : ${FUNCNAME[*]}" # (a)
echo

f1
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -

Ex : $ traceAppels
Debut :
FUNCNAME :
tableau FUNCNAME[] : (a)
--- Dans f1 :
--- FUNCNAME : f1
--- tableau FUNCNAME[] : f1 main (b)
--- - Appel a f2

------ Dans f2 :
------ FUNCNAME : f2
------ tableau FUNCNAME[] : f2 f1 main (c)
$

4. Arguments dune fonction

Les arguments dune fonction sont rfrencs dans son corps de la mme manire que les
arguments dun programme shell le sont : $1 rfrence le premier argument, $2 le deuxime,
etc., $# le nombre darguments passs lors de lappel de la fonction.
Le paramtre spcial $0 nest pas modifi : il contient le nom du programme shell.

Pour viter toute confusion avec les paramtres de position qui seraient ventuellement
initialiss dans le code appelant la fonction, la valeur de ces derniers est sauvegarde avant
lappel la fonction puis restitue aprs excution de la fonction.

133
Le programme shell args illustre ce mcanisme de sauvegarde/restitution :

args
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -
#!/bin/bash

function f
{
echo " --- Dans f : \$0 : $0"
echo " --- Dans f : \$# : $#"
echo " --- Dans f : \$1 : $1" => affichage du 1er argument de la fonction f
}

echo "Avant f : \$0 : $0"


echo "Avant f : \$# : $#"
echo "Avant f : \$1 : $1" => affichage du 1er argument du programme args
f pierre paul jacques
echo "Apres f : \$1 : $1" => affichage du 1er argument du programme args
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -

Ex : $ args un deux trois quatre


Avant f : $0 : ./args => nom du programme
Avant f : $# : 4 => nombre darguments passs args
Avant f : $1 : un => 1er argument pass args
--- Dans f : $0 : ./args
--- Dans f : $# : 3
--- Dans f : $1 : pierre => 1er argument pass la fonction f
Apres f : $1 : un => les arguments passs args ont t restitus
$

Utilise dans le corps dune fonction, la commande interne shift dcale la numrotation des
paramtres de position internes la fonction.

argsShift
-----------------------------------
#!/bin/bash

function f
{
echo " --- Dans f : Avant 'shift 2' : \$* : $*"
shift 2
echo " --- Dans f : Apres 'shift 2' : \$* : $*"
}

echo Appel : f un deux trois quatre


f un deux trois quatre
-----------------------------------

Ex : $ argsShift
Appel : f un deux trois quatre
--- Dans f : Avant 'shift 2' : $* : un deux trois quatre
--- Dans f : Apres 'shift 2' : $* : trois quatre
$

134
Quelle soit utilise dans une fonction ou lextrieur de celle-ci, la commande interne set
modifie toujours la valeur des paramtres de position.

argsSet
-----------------------------------
#!/bin/bash

function f
{
echo " -- Dans f : Avant execution de set \$(date) : \$* : $*"
set $(date)
echo " -- Dans f : Apres execution de set \$(date) : \$* : $*"
}

echo "Avant f : $*"


echo Appel : f alpha beta
f alpha beta
echo "Apres f : $*"
-----------------------------------

Ex : $ argsSet un
Avant f : un
Appel : f alpha beta
-- Dans f : Avant execution de set $(date) : $* : alpha beta
-- Dans f : Apres execution de set $(date) : $* : vendredi 18 avril
2014, 16:04:50 (UTC+0200)
Apres f : un => largument a t convenablement sauvegard puis restitu
$

5. Variables locales une fonction

Par dfaut, une variable dfinie lintrieur dune fonction est globale ; cela signifie quelle
est directement modifiable par les autres fonctions du programme shell.

Dans le programme shell glob, la fonction fUn est appele en premier. Celle-ci cre et
initialise la variable var. Puis la fonction fDeux est appele et modifie la variable (globale)
var. Enfin, cette variable est nouveau modifie puis sa valeur est affiche.

glob
-----------------------------------
#!/bin/bash

function fUn
{
var=Un # creation de la variable var
}

function fDeux
{
var=${var}Deux # premiere modification de var
}

fUn

135
fDeux
var=${var}Princ # deuxieme modification de var

echo $var
-----------------------------------

Ex : $ glob
UnDeuxPrinc => trace des modifications successives de la variable globale var
$

Pour dfinir une variable locale une fonction, on utilise la commande interne local. Sa
syntaxe est :
local [option(s)] [nom[=valeur] ...]

Les options utilisables avec local sont celles de la commande interne declare. Par consquent,
on dfinira une ou plusieurs variables locales de type entier avec la syntaxe local i (mais
aussi local a pour un tableau classique, local A pour un tableau associatif).

Le programme shell loc dfinit une variable entire a locale la fonction f1. Cette variable
nest pas accessible lextrieur de cette fonction.

loc
-----------------------------------
#!/bin/bash

function f1
{
local -i a=12 => a est une variable locale f1
(( a++ ))
echo "-- Dans f1 : a = $a"
}

f1
echo "Dans main : a = $a" => tentative daccs la valeur de a
-----------------------------------

Ex : $ loc
-- Dans f1 : a = 13
Dans main : a = => a nest pas visible dans le corps du programme
$

La porte d'une variable locale inclut la fonction qui l'a dfinie ainsi que les fonctions qu'elle
appelle (directement ou indirectement).

Dans le programme shell appelsCascade, la variable locale x est vue :


- dans la fonction f1 qui dfinit cette variable
- dans la fonction f2 qui est appele par la fonction f1
- dans la fonction f3 qui est appele par la fonction f2.

appelsCascade
-----------------------------------
#!/bin/bash

136
function f3
{
(( x = -x )) => modification de x dfinie dans la fonction f1
echo "f3 : x=$x (modification)"
}

function f2
{
echo "f2 : $((x+10))" => utilisation de x dfinie dans la fonction f1
f3 => appel de f3
}

function f1
{
local -i x => dfinition de x

x=2 => initialisation de x


echo "f1 : x=$x (initialisation)"
f2 => appel de f2
echo "f1 : Valeur finale : x=$x"
}

f1 => appel de f1
-----------------------------------

Ex : $ appelsCascade
f1 : x=2 (initialisation)
f2 : 12
f3 : x=-2 (modification)
f1 : Valeur finale : x=-2
$

La fonction f3 affecte la valeur -2 la variable x prcdemment initialise la valeur 2 dans la


fonction f1. A la fin de lexcution de f3, la valeur de x reste gale -2 dans la fonction
initiale f1.

6. Exporter une fonction

Pour quune fonction puisse tre excute par un programme shell diffrent de celui o elle a
t dfinie, il est ncessaire dexporter cette fonction. On utilise la commande interne export.

Syntaxe : export -f nomfct ...

Pour que lexport fonctionne, le sous-shell qui excute la fonction doit avoir une relation de
descendance avec le programme shell qui exporte la fonction.

Le programme shell progBonj dfinit et utilise une fonction bonj. Ce script lance lexcution
dun programme shell autreProgShell qui utilise galement la fonction bonj (mais qui ne la
dfinit pas) ; autreProgShell tant excut dans un environnement diffrent de progBonj, il ne
pourra trouver la dfinition de la fonction bonj : une erreur dexcution se produit.

137
progBonj
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -
#!/bin/bash

function bonj
{
echo bonj : Bonjour $1
}

bonj Madame

autreProgShell
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -

autreProgShell
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -
#!/bin/bash

echo appel a la fonction externe : bonj


bonj Monsieur
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -
Ex: $ progBonj
bonj : Bonjour Madame
appel a la fonction externe : bonj
./autreProgShell: line 4: bonj : commande introuvable
$

Pour que la fonction bonj puisse tre excute par autreProgShell, il suffit que le programme
shell qui la contient exporte sa dfinition.

progBonjExport
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - -
#!/bin/bash

function bonj
{
echo bonj : Bonjour $1
}

export -f bonj => la fonction bonj est exporte


bonj Madame

autreProgShell
-----------------------------------

Aprs son export, la fonction bonj sera connue dans les sous-shells crs lors de lexcution
de progBonjExport.

Ex : $ progBonjExport
bonj : Bonjour Madame
appel a la fonction externe : bonj
bonj : Bonjour Monsieur => affich lors de lexcution de autreProgShell
$

138
La visibilit dune fonction exporte est similaire celle dune variable locale, c'est--dire une
visibilit arborescente dont la racine est le point dexport de la fonction.

Le programme shell progBonjExport2Niv dfinit et exporte la fonction bonj. Aprs avoir


utilise la fonction bonj (bonj Madame), il excute le programme autreProg1.
Le programme autreProg1 utilise la fonction bonj (bonj Monsieur) puis excute le
programme autreProg2.
Le programme autreProg2 utilise la fonction bonj (bonj Mademoiselle) puis se termine.

progBonjExport2Niv
-----------------------------------
#!/bin/bash

function bonj
{
echo bonj : Bonjour $1
}

export -f bonj

bonj Madame

autreProg1
-----------------------------------

autreProg1
-----------------------------------
#!/bin/bash

echo "$0 : appel a la fonction externe : bonj"


bonj Monsieur

autreProg2
-----------------------------------

autreProg2
-----------------------------------
#!/bin/bash

echo "$0 : appel a la fonction externe : bonj"


bonj Mademoiselle
-----------------------------------

Ex : $ progBonjExport2Niv
bonj : Bonjour Madame
./autreProg1 : appel a la fonction externe : bonj
bonj : Bonjour Monsieur
./autreProg2 : appel a la fonction externe : bonj
bonj : Bonjour Mademoiselle
$

7. Commande interne return

Syntaxe : return [ n ]

139
La commande interne return permet de sortir dune fonction avec comme code de retour la
valeur n (0 255). Celle-ci est mmorise dans le paramtre spcial ?.
Si n n'est pas prcis, le code de retour fourni est celui de la dernire commande excute par
la fonction.

Dans le programme shell return0, la fonction f retourne le code de retour 5 au corps du


programme shell.

retour0
-----------------------------------
#!/bin/bash

function f
{
echo coucou
return 5
echo a demain # jamais execute
}

f
echo code de retour de f : $?
-----------------------------------

Ex : $ return0
coucou
code de retour de f : 5
$

Remarque : il ne faut pas confondre return et exit. Cette dernire arrte lexcution du
programme shell qui la contient.

8. Substitution de fonction

La commande interne return ne peut retourner quun code de retour. Pour rcuprer la valeur
modifie par une fonction, on peut :
- enregistrer la nouvelle valeur dans une variable globale, ou
- faire crire la valeur modifie sur la sortie standard, ce qui permet la fonction ou
programme appelant de capter cette valeur grce une substitution de fonction :
$( fct [ arg ] ).

recupres
-----------------------------------
#!/bin/bash

function ajouteCoucou
{
echo $1 coucou
}

echo la chaine est : $( ajouteCoucou bonjour )


-----------------------------------

La fonction ajouteCoucou prend un argument et lui concatne la chane coucou. La chane

140
rsultante est crite sur la sortie standard afin dtre rcupre par lappelant.

Ex : $ recupres
La chaine est: bonjour coucou
$

9. Fonctions rcursives

Comme pour les programmes shell, bash permet lcriture de fonctions rcursives.

Le programme fctfactr implante le calcul dune factorielle sous la forme dune fonction shell f
rcursive. Outre la rcursivit, ce programme illustre
- la dfinition dune fonction au milieu dun programme shell
- la substitution de fonction.

fctfactr
-----------------------------------
#!/bin/bash

shopt -s extglob

if (( $# != 1 )) || [[ $1 != +([0-9]) ]]
then
echo "syntaxe : fctfactr n" >&2
exit 1
fi

function f
{
local -i n

if (( $1 == 0 ))
then echo 1
else
(( n=$1-1 ))
n=$( f $n ) => appel rcursif
echo $(( $1 * $n ))
fi
}

f $1
-----------------------------------

Ex : $ fctfactr
syntaxe : fctfactr n
$ fctfactr euzte12uz
syntaxe : fctfactr n
$ fctfactr 1
1
$ fctfactr 4
24
$

141
10. Appels de fonctions disperses dans plusieurs fichiers

Lorsque les fonctions dun programme shell sont places dans diffrents fichiers, on excute
ces derniers dans lenvironnement du fichier shell principal . Cela revient excuter
plusieurs fichiers shell dans un mme environnement.

Dans lexemple ci-dessous, pour que la fonction f dfinie dans le fichier def_f puisse tre
accessible depuis le fichier shell appel, on excute def_f dans lenvironnement de appel (en
utilisant la commande interne source ou .). Seule la permission lecture est ncessaire pour
def_f.

appel
-----------------------------------
#!/bin/bash

source def_f # ou plus court : . def_f


# Permissions de def_f : r--r--r--

x=2
f # appel de la fonction f contenue dans def_f
-----------------------------------

def_f
-----------------------------------
#!/bin/bash

function f
{
echo $((x+2))
}
-----------------------------------

Ex : $ appel
4
$

142

Вам также может понравиться

  • kubernetes.fr
    kubernetes.fr
    Документ51 страница
    kubernetes.fr
    Steve Fotso
    0% (1)
  • IntroProgBash 2015-07-16
    IntroProgBash 2015-07-16
    Документ143 страницы
    IntroProgBash 2015-07-16
    Steve Fotso
    Оценок пока нет
  • Debuter Sur Adobe Photoshop
    Debuter Sur Adobe Photoshop
    Документ575 страниц
    Debuter Sur Adobe Photoshop
    Steve Fotso
    Оценок пока нет
  • Photoshop Cs Se Former FR PDF
    Photoshop Cs Se Former FR PDF
    Документ506 страниц
    Photoshop Cs Se Former FR PDF
    Steve Fotso
    100% (1)
  • Module 4ccna 200-120
    Module 4ccna 200-120
    Документ95 страниц
    Module 4ccna 200-120
    Steve Fotso
    Оценок пока нет
  • Cours-Base DE Donnée
    Cours-Base DE Donnée
    Документ114 страниц
    Cours-Base DE Donnée
    labraidji
    100% (4)
  • Cours VBA
    Cours VBA
    Документ77 страниц
    Cours VBA
    Steve Fotso
    Оценок пока нет
  • Fonctionnalites WinDev
    Fonctionnalites WinDev
    Документ177 страниц
    Fonctionnalites WinDev
    Monssif Najim
    Оценок пока нет
  • Simbox
    Simbox
    Документ5 страниц
    Simbox
    Steve Fotso
    Оценок пока нет
  • Librairie PHPExcel, Crée... Dit Développement Web
    Librairie PHPExcel, Crée... Dit Développement Web
    Документ5 страниц
    Librairie PHPExcel, Crée... Dit Développement Web
    Steve Fotso
    Оценок пока нет
  • Les TPS de Java PDF
    Les TPS de Java PDF
    Документ67 страниц
    Les TPS de Java PDF
    Momed
    Оценок пока нет
  • Cours 4 Les TWIGs PDF
    Cours 4 Les TWIGs PDF
    Документ27 страниц
    Cours 4 Les TWIGs PDF
    Nour Kchaou
    Оценок пока нет
  • Automatiser Les Réseaux Avec Ansible Guide Technique Pour L'administrateur - Damien Perrin (2022)
    Automatiser Les Réseaux Avec Ansible Guide Technique Pour L'administrateur - Damien Perrin (2022)
    Документ110 страниц
    Automatiser Les Réseaux Avec Ansible Guide Technique Pour L'administrateur - Damien Perrin (2022)
    Bonkatibi djidda
    Оценок пока нет
  • Introduction Batch
    Introduction Batch
    Документ17 страниц
    Introduction Batch
    muzoxi
    100% (1)
  • Guide Devops
    Guide Devops
    Документ43 страницы
    Guide Devops
    Moez
    Оценок пока нет
  • Dba 1 Chakraoui Med
    Dba 1 Chakraoui Med
    Документ186 страниц
    Dba 1 Chakraoui Med
    taoufik louhz
    Оценок пока нет
  • Commande MSDOS
    Commande MSDOS
    Документ2 страницы
    Commande MSDOS
    asmakorib
    Оценок пока нет
  • Cours Soa
    Cours Soa
    Документ26 страниц
    Cours Soa
    Kalilou Berthe
    Оценок пока нет
  • Abs-5 1 04
    Abs-5 1 04
    Документ698 страниц
    Abs-5 1 04
    albebert
    Оценок пока нет
  • Open Source
    Open Source
    Документ35 страниц
    Open Source
    achraf
    Оценок пока нет
  • Unix PDF
    Unix PDF
    Документ108 страниц
    Unix PDF
    zakaria rouissiya
    Оценок пока нет
  • 1 - Introduction Spring
    1 - Introduction Spring
    Документ46 страниц
    1 - Introduction Spring
    Stray Dog
    Оценок пока нет
  • Exos Corrigés Shell
    Exos Corrigés Shell
    Документ38 страниц
    Exos Corrigés Shell
    Mohamed Aziz EL HORR
    100% (1)
  • Serie 3 Oracle
    Serie 3 Oracle
    Документ3 страницы
    Serie 3 Oracle
    hfsaa
    Оценок пока нет
  • TP 1 Admin Unix Linux 17
    TP 1 Admin Unix Linux 17
    Документ4 страницы
    TP 1 Admin Unix Linux 17
    d'Assise SANOU
    Оценок пока нет
  • Tutoriel de Reconnaissance Faciale Python - Nitratine
    Tutoriel de Reconnaissance Faciale Python - Nitratine
    Документ18 страниц
    Tutoriel de Reconnaissance Faciale Python - Nitratine
    Badiane Badiane
    Оценок пока нет
  • Installer IIS Et PHP
    Installer IIS Et PHP
    Документ4 страницы
    Installer IIS Et PHP
    Ludo Bde
    Оценок пока нет
  • WSH 04
    WSH 04
    Документ36 страниц
    WSH 04
    jaimeleloiret
    Оценок пока нет
  • Matlab Octave Cours JDBonjour 2014 09 24 PDF
    Matlab Octave Cours JDBonjour 2014 09 24 PDF
    Документ163 страницы
    Matlab Octave Cours JDBonjour 2014 09 24 PDF
    Bepito Dikanda
    Оценок пока нет
  • Laravel FR PDF
    Laravel FR PDF
    Документ229 страниц
    Laravel FR PDF
    Issam Elyazri
    100% (2)
  • Diapo 3
    Diapo 3
    Документ21 страница
    Diapo 3
    Med Loutt Horma Babana
    Оценок пока нет
  • Système D'exploitation
    Système D'exploitation
    Документ69 страниц
    Système D'exploitation
    elkamondo
    50% (2)
  • TP1
    TP1
    Документ17 страниц
    TP1
    Abdelali Moufidi
    Оценок пока нет
  • 44444
    44444
    Документ30 страниц
    44444
    najat bus
    Оценок пока нет
  • Cours 2 OI
    Cours 2 OI
    Документ45 страниц
    Cours 2 OI
    Benzaidan Rida
    Оценок пока нет
  • Poly GI53 Unix
    Poly GI53 Unix
    Документ75 страниц
    Poly GI53 Unix
    Achfakidine Jaovitahermann
    Оценок пока нет
  • Rar
    Rar
    Документ47 страниц
    Rar
    Serby Røyal
    Оценок пока нет
  • Polycopie Shell
    Polycopie Shell
    Документ14 страниц
    Polycopie Shell
    david Abotsitse
    Оценок пока нет
  • Les Commande DOS
    Les Commande DOS
    Документ4 страницы
    Les Commande DOS
    Axel ODG
    Оценок пока нет
  • Unix 1
    Unix 1
    Документ119 страниц
    Unix 1
    saaoud96
    Оценок пока нет