Vous êtes sur la page 1sur 662

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

bash
Le livre de recettes

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

CARL ALBING, JP VOSSEN ET


CAMERON NEWHAM

bash
Le livre de recettes

Traduction de FRANOIS CERBELLE et HERV SOULARD

ditions OREILLY
18 rue Sguier
75006 Paris
france@oreilly.com
http://www.oreilly.fr/

Cambridge Cologne Farnham Paris Pkin Sebastopol Taipei Tokyo


[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Ldition originale de ce livre a t publie aux tats-Unis par OReilly Media Inc. sous
le titre bash Cookbook, ISBN 0-596-52678-4.
OReilly Media Inc., 2007

Couverture conue par Karen MONTGOMERY et Marcia FRIEDMAN

dition franaise : Dominique BURAUD

Les programmes figurant dans ce livre ont pour but dillustrer les sujets traits. Il nest
donn aucune garantie quant leur fonctionnement une fois compils, assembls ou
interprts dans le cadre dune utilisation professionnelle ou commerciale.

DITIONS OREILLY, Paris, 2007


ISBN 10 : 2-35402-083-X
ISBN 13 : 978-2-35402-083-5
Version papier : http://www.oreilly.fr/catalogue/2841774473

Toute reprsentation ou reproduction, intgrale ou partielle, faite sans le consentement de lauteur, de


ses ayants droit, ou ayants cause, est illicite (loi du 11 mars 1957, alina 1er de larticle 40). Cette reprsentation ou reproduction, par quelque procd que ce soit, constituerait une contrefaon sanctionne
par les articles 425 et suivants du Code pnal. La loi du 11 mars 1957 autorise uniquement, aux termes
des alinas 2 et 3 de larticle 41, les copies ou reproductions strictement rserves lusage priv du copiste et non destines une utilisation collective dune part et, dautre part, les analyses et les courtes
citations dans un but dexemple et dillustration.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Table des matires

Prface ................................................................................................. xv
1. Dbuter avec bash .......................................................................... 1
1.1.
1.2.
1.3.
1.4.
1.5.
1.6.
1.7.
1.8.
1.9.
1.10.
1.11.
1.12.
1.13.
1.14.
1.15.
1.16.

Comprendre linvite de commandes ..................................................... 4


Afficher son emplacement ...................................................................... 5
Chercher et excuter des commandes .................................................... 6
Obtenir des informations sur des fichiers .............................................. 8
Afficher tous les fichiers cachs ............................................................ 10
Protger la ligne de commande ............................................................ 12
Utiliser ou remplacer des commandes ................................................ 14
Dterminer si le shell est en mode interactif ...................................... 15
Faire de bash le shell par dfaut ........................................................... 16
Obtenir bash pour Linux ...................................................................... 18
Obtenir bash pour xBSD ....................................................................... 21
Obtenir bash pour Mac OS X ................................................................ 22
Obtenir bash pour Unix ........................................................................ 23
Obtenir bash pour Windows ................................................................ 24
Obtenir bash sans linstaller .................................................................. 25
Documentation de bash ........................................................................ 26

2. Sortie standard ............................................................................. 31


2.1.
2.2.
2.3.
2.4.
2.5.
2.6.

[05/03/08]

bash Le livre de recettes

crire la sortie sur le terminal ou une fentre ....................................


crire la sortie en conservant les espaces .............................................
Mettre en forme la sortie ......................................................................
crire la sortie sans le saut de ligne ......................................................
Enregistrer la sortie dune commande .................................................
Enregistrer la sortie vers dautres fichiers ............................................

32
33
34
35
36
37

Elodie FRITSCH <elodie.fritsch@total.com>

vi

Table des matires


2.7.
2.8.
2.9.
2.10.
2.11.
2.12.
2.13.
2.14.
2.15.
2.16.
2.17.
2.18.
2.19.
2.20.
2.21.
2.22.

Enregistrer la sortie de la commande ls ...............................................


Envoyer la sortie et les erreurs vers des fichiers diffrents .................
Envoyer la sortie et les erreurs vers le mme fichier ..........................
Ajouter la sortie un fichier existant ..................................................
Utiliser seulement le dbut ou la fin dun fichier ...............................
Sauter len-tte dun fichier ..................................................................
Oublier la sortie .....................................................................................
Enregistrer ou runir la sortie de plusieurs commandes ...................
Relier une sortie une entre ..............................................................
Enregistrer une sortie redirige vers une entre .................................
Connecter des programmes en utilisant la sortie comme argument
Placer plusieurs redirections sur la mme ligne .................................
Enregistrer la sortie lorsque la redirection semble inoprante .........
Permuter STDERR et STDOUT ...........................................................
Empcher lcrasement accidentel des fichiers ...................................
craser un fichier la demande ...........................................................

38
39
40
41
42
43
43
44
46
47
49
50
51
53
54
56

3. Entre standard ............................................................................ 59


3.1.
3.2.
3.3.
3.4.
3.5.
3.6.
3.7.
3.8.

Lire les donnes dentre depuis un fichier .........................................


Conserver les donnes avec le script ....................................................
Empcher un comportement trange dans un here document ........
Indenter un here document .................................................................
Lire lentre de lutilisateur ..................................................................
Attendre une rponse Oui ou Non ......................................................
Choisir dans une liste doptions ...........................................................
Demander un mot de passe ..................................................................

59
60
61
63
64
65
68
69

4. Excuter des commandes ............................................................. 71


4.1.
4.2.
4.3.
4.4.
4.5.
4.6.
4.7.
4.8.
4.9.
4.10.

Lancer nimporte quel excutable ........................................................


Connatre le rsultat de lexcution dune commande .....................
Excuter plusieurs commandes la suite ............................................
Excuter plusieurs commandes la fois ..............................................
Dterminer le succs dune commande ...............................................
Utiliser moins dinstructions if .............................................................
Lancer de longues tches sans surveillance .........................................
Afficher des messages en cas derreur ..................................................
Excuter des commandes places dans une variable ..........................
Excuter tous les scripts dun rpertoire ..............................................

71
73
75
76
77
78
79
80
81
82

5. Variables du shell ......................................................................... 85


5.1. Documenter un script ........................................................................... 87
5.2. Incorporer la documentation dans les scripts ..................................... 88
5.3. Amliorer la lisibilit des scripts .......................................................... 90

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Table des matires


5.4.
5.5.
5.6.
5.7.
5.8.
5.9.
5.10.
5.11.
5.12.
5.13.
5.14.
5.15.
5.16.
5.17.
5.18.
5.19.

vii

Sparer les noms de variables du texte environnant .......................... 92


Exporter des variables ........................................................................... 92
Afficher les valeurs de toutes les variables ........................................... 94
Utiliser des paramtres dans un script ................................................. 95
Parcourir les arguments dun script ..................................................... 96
Accepter les paramtres contenant des espaces .................................. 97
Accepter des listes de paramtres contenant des espaces ................... 99
Compter les arguments ....................................................................... 101
Extraire certains arguments ................................................................ 103
Obtenir des valeurs par dfaut ........................................................... 104
Fixer des valeurs par dfaut ................................................................ 105
Utiliser null comme valeur par dfaut valide ................................... 106
Indiquer une valeur par dfaut variable ............................................ 107
Afficher un message derreur pour les paramtres non dfinis ....... 108
Modifier certaines parties dune chane ............................................ 109
Utiliser les tableaux ............................................................................. 111

6. Logique et arithmtique ............................................................. 113


6.1.
6.2.
6.3.
6.4.
6.5.
6.6.
6.7.
6.8.
6.9.
6.10.
6.11.
6.12.
6.13.
6.14.
6.15.
6.16.
6.17.
6.18.
6.19.

Utiliser larithmtique dans un script ................................................


Conditionner lexcution du code .....................................................
Tester les caractristiques des fichiers ................................................
Tester plusieurs caractristiques .........................................................
Tester les caractristiques des chanes ................................................
Tester lgalit ......................................................................................
Tester avec des correspondances de motifs ........................................
Tester avec des expressions rgulires ................................................
Modifier le comportement avec des redirections .............................
Boucler avec while ...............................................................................
Boucler avec read .................................................................................
Boucler avec un compteur ..................................................................
Boucler avec des valeurs en virgule flottante ....................................
Raliser des branchements multiples ................................................
Analyser les arguments de la ligne de commande ............................
Crer des menus simples .....................................................................
Modifier linvite des menus simples ..................................................
Crer une calculatrice NPI simple .....................................................
Crer une calculatrice en ligne de commande ..................................

113
116
119
122
123
124
126
127
130
131
133
135
136
137
139
142
143
144
147

7. Outils shell intermdiaires I ...................................................... 149


7.1.
7.2.
7.3.
7.4.

[05/03/08]

bash Le livre de recettes

Rechercher une chane dans des fichiers ...........................................


Garder uniquement les noms de fichiers ..........................................
Obtenir une rponse vrai/faux partir dune recherche ..................
Rechercher une chane en ignorant la casse ......................................

150
151
152
154

Elodie FRITSCH <elodie.fritsch@total.com>

viii

Table des matires


7.5.
7.6.
7.7.
7.8.
7.9.
7.10.
7.11.
7.12.
7.13.
7.14.
7.15.
7.16.

Effectuer une recherche dans un tube ...............................................


Rduire les rsultats de la recherche ..................................................
Utiliser des motifs plus complexes dans la recherche .......................
Rechercher un numro de scu ..........................................................
Rechercher dans les fichiers compresss ............................................
Garder une partie de la sortie .............................................................
Conserver une partie dune ligne de sortie .......................................
Inverser les mots de chaque ligne ......................................................
Additionner une liste de nombres .....................................................
Compter des chanes ...........................................................................
Afficher les donnes sous forme dhistogramme ..............................
Afficher un paragraphe de texte aprs une phrase trouve .............

154
156
157
158
159
160
161
162
163
164
166
168

8. Outils shell intermdiaires II ..................................................... 171


8.1.
8.2.
8.3.
8.4.
8.5.
8.6.
8.7.
8.8.
8.9.
8.10.
8.11.
8.12.
8.13.
8.14.
8.15.

Trier votre affichage ............................................................................


Trier les nombres .................................................................................
Trier des adresses IP .............................................................................
Couper des parties de la sortie ............................................................
Retirer les lignes identiques ................................................................
Compresser les fichiers ........................................................................
Dcompresser des fichiers ...................................................................
Vrifier les rpertoires contenus dans une archive tar .....................
Substituer des caractres .....................................................................
Changer la casse des caractres ...........................................................
Convertir les fichiers DOS au format Linux/Unix ............................
Supprimer les guillemets ....................................................................
Compter les lignes, les mots ou les caractres dans un fichier ........
Reformater des paragraphes ...............................................................
Aller plus loin avec less .......................................................................

171
172
173
176
177
178
180
182
183
184
185
186
187
188
189

9. Rechercher des fichiers avec find, locate et slocate .................. 191


9.1.
9.2.
9.3.
9.4.
9.5.
9.6.
9.7.
9.8.
9.9.
9.10.
9.11.

[05/03/08]

bash Le livre de recettes

Retrouver tous vos fichiers MP3 ........................................................


Traiter les noms de fichiers contenant des caractres tranges .......
Acclrer le traitement des fichiers trouvs ......................................
Suivre les liens symboliques ...............................................................
Retrouver des fichiers sans tenir compte de la casse ........................
Retrouver des fichiers daprs une date .............................................
Retrouver des fichiers daprs leur type .............................................
Retrouver des fichiers daprs leur taille ...........................................
Retrouver des fichiers daprs leur contenu ......................................
Retrouver rapidement des fichiers ou du contenu ...........................
Retrouver un fichier partir dune liste
demplacements possibles ...................................................................

191
193
194
195
195
196
197
198
199
200
202

Elodie FRITSCH <elodie.fritsch@total.com>

Table des matires

ix

10. Autres fonctionnalits pour les scripts ...................................... 207


10.1.
10.2.
10.3.
10.4.
10.5.
10.6.
10.7.
10.8.

Convertir un script en dmon ............................................................


Rutiliser du code ................................................................................
Utiliser des fichiers de configuration dans un script ........................
Dfinir des fonctions ...........................................................................
Utiliser des fonctions : paramtres et valeur de retour ....................
Intercepter les signaux ........................................................................
Redfinir des commandes avec des alias ............................................
Passer outre les alias ou les fonctions ................................................

207
208
210
211
213
215
219
221

11. Dates et heures ........................................................................... 223


11.1.
11.2.
11.3.
11.4.
11.5.
11.6.
11.7.
11.8.

Formater les dates en vue de leur affichage ......................................


Fournir une date par dfaut ...............................................................
Calculer des plages de dates ................................................................
Convertir des dates et des heures en secondes depuis lorigine .......
Convertir des secondes depuis lorigine en dates et heures .............
Dterminer hier ou demain en Perl ..................................................
Calculer avec des dates et des heures .................................................
Grer les fuseaux horaires, les horaires dt et
les annes bissextiles ............................................................................
11.9. Utiliser date et cron pour excuter un script au nme jour ............

224
225
227
230
231
232
233
235
235

12. Tches utilisateur sous forme de scripts shell ........................... 239


12.1.
12.2.
12.3.
12.4.
12.5.

Afficher une ligne de tirets .................................................................


Prsenter des photos dans un album .................................................
Charger votre lecteur MP3 .................................................................
Graver un CD .......................................................................................
Comparer deux documents ................................................................

239
241
247
251
254

13. Analyses et tches similaires ..................................................... 257


13.1.
13.2.
13.3.
13.4.
13.5.
13.6.
13.7.
13.8.
13.9.
13.10.
13.11.
13.12.
13.13.

[05/03/08]

bash Le livre de recettes

Analyser les arguments dun script ....................................................


Afficher ses propres messages derreur lors de lanalyse ..................
Analyser du contenu HTML ...............................................................
Placer la sortie dans un tableau ..........................................................
Analyser la sortie avec une fonction ..................................................
Analyser du texte avec read ................................................................
Analyser avec read dans un tableau ...................................................
Dterminer le bon accord ...................................................................
Analyser une chane caractre par caractre .....................................
Nettoyer une arborescence SVN ........................................................
Configurer une base de donnes MySQL ..........................................
Extraire certains champs des donnes ...............................................
Actualiser certains champs dans des fichiers de donnes .................

257
260
262
264
265
266
267
268
269
270
271
273
276

Elodie FRITSCH <elodie.fritsch@total.com>

Table des matires


13.14.
13.15.
13.16.
13.17.
13.18.
13.19.

Supprimer les espaces ..........................................................................


Compacter les espaces .........................................................................
Traiter des enregistrements de longueur fixe ....................................
Traiter des fichiers sans sauts de ligne ................................................
Convertir un fichier de donnes au format CSV ..............................
Analyser un fichier CSV ......................................................................

277
281
283
285
287
288

14. Scripts scuriss .......................................................................... 291


14.1.
14.2.
14.3.
14.4.
14.5.
14.6.
14.7.
14.8.
14.9.
14.10.
14.11.
14.12.
14.13.
14.14.
14.15.
14.16.
14.17.
14.18.
14.19.
14.20.
14.21.
14.22.
14.23.

viter les problmes de scurit classiques ........................................


viter lusurpation de linterprteur ..................................................
Dfinir une variable $PATH sre ......................................................
Effacer tous les alias .............................................................................
Effacer les commandes mmorises ...................................................
Interdire les fichiers core .....................................................................
Dfinir une variable $IFS sre ...........................................................
Dfinir un umask sr ..........................................................................
Trouver les rpertoires modifiables mentionns dans $PATH .......
Ajouter le rpertoire de travail dans $PATH ....................................
Utiliser des fichiers temporaires scuriss .........................................
Valider lentre ....................................................................................
Fixer les autorisations ..........................................................................
Afficher les mots de passe dans la liste des processus .......................
crire des scripts setuid ou setgid .......................................................
Restreindre les utilisateurs invits ......................................................
Utiliser un environnement chroot .....................................................
Excuter un script sans avoir les privilges de root ..........................
Utiliser sudo de manire plus sre .....................................................
Utiliser des mots de passe dans un script ...........................................
Utiliser SSH sans mot de passe ...........................................................
Restreindre les commandes SSH ........................................................
Dconnecter les sessions inactives ......................................................

293
294
294
296
297
298
298
299
300
303
304
308
310
311
312
314
316
317
318
319
321
329
331

15. Scripts labors ........................................................................... 333


15.1.
15.2.
15.3.
15.4.
15.5.
15.6.
15.7.
15.8.
15.9.
15.10.

[05/03/08]

bash Le livre de recettes

Trouver bash de manire portable .....................................................


Dfinir une variable $PATH de type POSIX .....................................
Dvelopper des scripts shell portables ...............................................
Tester des scripts sous VMware ..........................................................
crire des boucles portables ................................................................
crire une commande echo portable .................................................
Dcouper lentre si ncessaire ...........................................................
Afficher la sortie en hexadcimal .......................................................
Utiliser la redirection du rseau de bash ...........................................
Dterminer mon adresse .....................................................................

334
335
337
339
340
342
345
346
348
349

Elodie FRITSCH <elodie.fritsch@total.com>

Table des matires


15.11.
15.12.
15.13.
15.14.
15.15.
15.16.

xi

Obtenir lentre depuis une autre machine ......................................


Rediriger la sortie pour toute la dure dun script ...........................
Contourner les erreurs liste darguments trop longue ..............
Journaliser vers syslog depuis un script .............................................
Envoyer un message lectronique depuis un script ..........................
Automatiser un processus plusieurs phases ...................................

354
356
357
359
360
363

16. Configurer bash .......................................................................... 367


16.1.
16.2.
16.3.
16.4.
16.5.
16.6.
16.7.
16.8.
16.9.
16.10.
16.11.
16.12.
16.13.
16.14.
16.15.
16.16.
16.17.
16.18.
16.19.
16.20.

Options de dmarrage de bash ...........................................................


Personnaliser linvite ...........................................................................
Modifier dfinitivement $PATH ........................................................
Modifier temporairement $PATH .....................................................
Dfinir $CDPATH ...............................................................................
Raccourcir ou modifier des noms de commandes ............................
Adapter le comportement et lenvironnement du shell ..................
Ajuster le comportement de readline en utilisant .inputrc .............
Crer son rpertoire priv dutilitaires ..............................................
Utiliser les invites secondaires : $PS2, $PS3 et $PS4 .........................
Synchroniser lhistorique du shell entre des sessions .......................
Fixer les options de lhistorique du shell ...........................................
Concevoir une meilleure commande cd ...........................................
Crer un nouveau rpertoire et y aller avec une seule commande
Aller au fond des choses ......................................................................
tendre bash avec des commandes internes chargeables .................
Amliorer la compltion programmable ..........................................
Utiliser correctement les fichiers dinitialisation ..............................
Crer des fichiers dinitialisation autonomes et portables ...............
Commencer une configuration personnalise ..................................

368
368
376
377
383
385
386
387
389
390
392
393
396
398
399
400
406
411
414
416

17. Maintenance et tches administratives .................................... 429


17.1.
17.2.
17.3.
17.4.
17.5.
17.6.
17.7.
17.8.
17.9.
17.10.
17.11.
17.12.

[05/03/08]

bash Le livre de recettes

Renommer plusieurs fichiers ..............................................................


Utiliser GNU Texinfo et Info sous Linux ..........................................
Dzipper plusieurs archives ZIP .........................................................
Restaurer des sessions dconnectes avec screen ..............................
Partager une unique session bash ......................................................
Enregistrer une session complte ou un traitement par lots ...........
Effacer lcran lorsque vous vous dconnectez .................................
Capturer les mta-informations des fichiers pour une restauration
Indexer de nombreux fichiers ............................................................
Utiliser diff et patch .............................................................................
Compter les diffrences dans des fichiers ..........................................
Effacer ou renommer des fichiers dont le nom comporte
des caractres spciaux ........................................................................

429
431
432
433
435
437
438
439
440
441
446
448

Elodie FRITSCH <elodie.fritsch@total.com>

xii

Table des matires


17.13.
17.14.
17.15.
17.16.
17.17.
17.18.
17.19.
17.20.
17.21.
17.22.
17.23.
17.24.

Insrer des en-ttes dans un fichier ....................................................


diter un fichier sans le dplacer .......................................................
Utiliser sudo avec un groupe de commandes ...................................
Trouver les lignes prsentes dans un fichier
mais pas dans un autre ........................................................................
Conserver les N objets les plus rcents ..............................................
Filtrer la sortie de ps sans afficher le processus grep ........................
Dterminer si un processus sexcute ................................................
Ajouter un prfixe ou un suffixe laffichage ...................................
Numroter les lignes ...........................................................................
crire des squences ............................................................................
muler la commande DOS pause ......................................................
Formater les nombres .........................................................................

449
452
454
456
460
463
464
465
467
469
471
472

18. Rduire la saisie ......................................................................... 475


18.1.
18.2.
18.3.
18.4.
18.5.
18.6.
18.7.

Naviguer rapidement entre des rpertoires quelconques ................


Rpter la dernire commande ..........................................................
Excuter une commande similaire ....................................................
Effectuer des substitutions sur plusieurs mots ..................................
Rutiliser des arguments .....................................................................
Terminer les noms automatiquement ...............................................
Assurer la saisie ....................................................................................

475
477
478
479
480
481
482

19. Bourdes du dbutant .................................................................. 485


19.1.
19.2.
19.3.
19.4.
19.5.
19.6.
19.7.
19.8.
19.9.
19.10.
19.11.
19.12.
19.13.
19.14.
19.15.

[05/03/08]

bash Le livre de recettes

Oublier les autorisations dexcution ................................................


Rsoudre les erreurs Aucun fichier ou rpertoire de ce type ....
Oublier que le rpertoire de travail nest pas dans $PATH .............
Nommer un script test ..................................................................
Sattendre pouvoir modifier les variables exportes ......................
Oublier des guillemets lors des affectations ......................................
Oublier que la correspondance de motifs trie
par ordre alphabtique ........................................................................
Oublier que les tubes crent des sous-shells ......................................
Rinitialiser le terminal ......................................................................
Supprimer des fichiers avec une variable vide ..................................
Constater un comportement trange de printf .................................
Vrifier la syntaxe dun script bash ....................................................
Dboguer des scripts ............................................................................
viter les erreurs commande non trouve avec les fonctions ...
Confondre caractres gnriques du shell et
expressions rgulires ..........................................................................

485
486
488
489
490
491
493
493
496
497
497
499
500
502
503

Elodie FRITSCH <elodie.fritsch@total.com>

Table des matires

xiii

A. Listes de rfrence ...................................................................... 505


B. Exemples fournis avec bash ....................................................... 559
C. Analyse de la ligne de commande .............................................. 569
D. Gestion de versions ..................................................................... 575
E. Compiler bash ............................................................................. 597
Index .................................................................................................. 605

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Prface

Tout systme dexploitation moderne dispose dun interprteur de commandes (un


shell), voire mme de plusieurs. Certains shells sont orients ligne de commande, comme celui tudi dans ce livre, tandis que dautres offrent une interface graphique, comme lExplorateur de Windows ou le Finder du Mac. Certaines personnes utiliseront
linterprteur de commande uniquement pour lancer leur application prfre et ny
retourneront qu la fermeture de leur session. Cependant, les interactions entre lutilisateur et le shell sont gnralement plus frquentes et plus labores. Mieux vous connatrez votre shell, plus vous serez rapide et efficace.
Que vous soyez administrateur systme, programmeur ou simple utilisateur, un script
shell pourra, dans certaines occasions, vous faire gagner du temps ou faciliter la rptition dune tche importante. Mme la dfinition dun simple alias, qui modifie ou raccourcit le nom dune commande souvent utilise, peut avoir un effet substantiel. Nous
allons nous intresser, entre autres, tous ces aspects.
Comme cest le cas avec tout langage de programmation gnral, il existe plusieurs manires deffectuer une tche. Parfois, il nexiste quune seule bonne manire, mais, le plus
souvent, vous avez le choix entre deux ou trois approches quivalentes. Celle que vous
choisissez dpend de votre style personnel, de votre crativit et de votre connaissance
des diffrentes commandes et techniques. Cela sapplique aussi bien nous, en tant
quauteurs, qu vous, en tant que lecteur. Dans la plupart des exemples, nous proposons une seule mthode et la mettons en uvre. Parfois, nous optons pour une mthode particulire et expliquons pourquoi nous pensons quil sagit de la meilleure. Nous
prsenterons, loccasion, plusieurs solutions quivalentes afin que vous puissiez choisir celle qui correspond le mieux vos besoins et votre environnement.
Quelquefois, vous devrez choisir entre un code efficace trs astucieux et un code plus
lisible. Nous nous tournons toujours vers le code le plus lisible. En effet, lexprience
nous a appris que la lisibilit du code astucieux crit aujourdhui nest plus la mme 6
ou 18 mois et 10 projets plus tard. Vous risquez alors de passer beaucoup de temps
vous interroger sur le fonctionnement de votre code. Faites-nous confiance : crivez du
code clair et bien document. Vous vous en fliciterez plus tard.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

xvi

Prface

Notre public
Ce livre est destin aux utilisateurs de systmes Unix ou Linux (et Mac compris), ainsi
quaux administrateurs qui peuvent se trouver chaque jour devant plusieurs systmes
diffrents. Il vous aidera crer des scripts qui vous permettront den faire plus, en
moins de temps, plus facilement et de manire plus cohrente que jamais.
Les utilisateurs dbutants apprcieront les sections qui concernent lautomatisation des
tches rptitives, les substitutions simples et la personnalisation de leur environnement afin quil soit plus agrable et peut-tre plus conforme leurs habitudes. Les utilisateurs expriments et les administrateurs trouveront de nouvelles solutions et des
approches diffrentes des tches courantes. Les utilisateurs avancs seront intresss
par tout un ensemble de techniques utilisables sur-le-champ, sans devoir se souvenir de
tous les dtails syntaxiques.
Cet ouvrage sadresse particulirement :

aux nophytes dUnix ou de Linux qui ont peu de connaissances du shell, mais qui
souhaitent dpasser la seule utilisation de la souris ;

aux utilisateurs dUnix ou de Linux expriments et aux administrateurs systme


qui recherchent des rponses rapides leurs questions concernant lcriture de
scripts shell ;

aux programmeurs travaillant dans un environnement Unix ou Linux (ou mme


Windows) qui veulent amliorer leur productivit ;

aux administrateurs systme qui dbutent sous Unix ou Linux ou qui viennent
dun environnement Windows et qui doivent se former rapidement ;

aux utilisateurs de Windows et les administrateurs systme expriments qui souhaitent disposer dun environnement puissant pour lexcution de scripts.

Ce livre ne sattardera pas longtemps sur les bases de lcriture de scripts shell. Pour cela, consultez Le shell bash de Cameron Newham (ditions OReilly) et Introduction aux
scripts shell de Nelson H.F. Beebe et Arnold Robbins (ditions OReilly). Notre objectif
est dapporter des solutions aux problmes classiques, en insistant sur la pratique et
non sur la thorie. Nous esprons que ce livre vous fera gagner du temps lorsque vous
rechercherez une solution ou essaierez de vous souvenir dune syntaxe. En ralit, ce
sont les raisons de la rdaction de cet ouvrage. Nous voulions un livre qui propose des
ides et permette de passer directement aux exemples pratiques oprationnels en cas
de besoin. Ainsi, nous navons pas mmoriser les diffrences subtiles entre le shell,
Perl, C, etc.
Nous supposons que vous avez accs un systme Unix ou Linux (ou bien, reportezvous la recette 1.15, page 25, ou la recette 15.4, page 339) et que vous savez comment
ouvrir une session, saisir des commandes basiques et utiliser un diteur de texte. Pour
la majorit des exemples, vous naurez pas besoin des droits du super-utilisateur (root).
En revanche, ils seront indispensables pour quelques-uns, notamment ceux qui concernent linstallation de bash.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Prface

xvii

Contenu de ce livre
Le sujet de cet ouvrage est bash, le GNU Bourne Again Shell. Il fait partie de la famille des
shells Bourne, dont les autres membres sont le shell Bourne originel, sh, le shell Korn,
ksh, ainsi que sa version pdksh (Public Domain Korn Shell). Bien quils ne soient pas au
cur de ce livre, tout comme dash et zsh, les scripts prsents fonctionneront assez bien
avec ces autres interprteurs de commandes.
Vous pouvez lire cet ouvrage du dbut la fin ou louvrir et slectionner ce qui retient
votre attention. Cela dit, nous esprons surtout que ds que vous aurez une question
sur la manire deffectuer une tche ou besoin dun conseil, vous pourrez trouver facilement la rponse adapte (ou proche) et conomiser du temps et des efforts.
La philosophie Unix tend construire des outils simples qui rpondent parfaitement
des problmes prcis, puis les combiner selon les besoins. Lassociation des outils se
fait gnralement au travers dun script shell car ces commandes, appeles tubes, peuvent tre longues et difficiles mmoriser ou saisir. Lorsque ce sera ncessaire, nous
emploierons ces outils dans le contexte dun script shell pour runir les diffrents lments qui permettent datteindre lobjectif vis.
Ce livre a t crit avec OpenOffice.org Writer sur la machine Linux ou Windows disponible un moment donn et en utilisant Subversion (voir lannexe D, Gestion de versions). Grce au format ODF (Open Document Format), de nombreux aspects de lcriture
de ce livre, comme les rfrences croises et lextraction de code, ont t simplifis (voir
la recette 13.17, page 285).

Logiciel GNU
bash, ainsi que dautres outils mentionns dans ce livre, font partie du projet GNU
(http://www.gnu.org/). GNU est un acronyme rcursif qui signifie en anglais GNUs Not
Unix (GNU nest pas Unix). Dmarr en 1984, ce projet a pour objectif de dvelopper
un systme dexploitation de type Unix libre.
Sans trop entrer dans les dtails, ce que lon nomme couramment Linux est, en ralit,
un noyau avec un ensemble minimal de diffrents logiciels. Les outils GNU se placent
autour de ce cur et bons nombres dautres logiciels peuvent tre inclus selon les distributions. Cependant, le noyau Linux lui-mme nest pas un logiciel GNU.
Le projet GNU dfend lide que Linux devrait en ralit se nommer GNU/Linux .
Cest galement lavis dautres acteurs et certaines distributions, notamment Debian,
emploie cette dnomination. Par consquent, on peut considrer que lobjectif du projet GNU a t atteint, mme si le rsultat nest pas exclusivement GNU.
De nombreux logiciels importants, en particulier bash, sont issus du projet GNU et il
existe des versions GNU de pratiquement tous les outils mentionns dans ce livre. Bien
que les outils fournis par ce projet soient plus riches en fonctionnalits et, en gnral,
plus faciles utiliser, ils sont galement parfois lgrement diffrents. Nous reviendrons
sur ce sujet la recette 15.3, page 337, mme si les fournisseurs dUnix commerciaux, entre les annes 1980 et 1990, sont largement responsables de ces diffrences.
Tous ces aspects de GNU, Unix et Linux ont dj t traits en dtail (dans des livres aussi pais que celui-ci), mais nous pensons que ces remarques taient ncessaires. Pour
plus dinformations sur le sujet, consultez le site http://www.gnu.org.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

xviii

Prface

Note sur les exemples de code


Les lments dexcution dun script shell sont gnralement prsents de la manire
suivante :
$ ls
a.out
$

cong.txt def.conf

fichier.txt autre.txt zebra.liste

Le premier caractre est souvent un symbole dollar ($) pour indiquer que la commande
a t saisie linvite du shell bash. (Noubliez pas quelle peut tre diffrente et que vous
pouvez la modifier, comme lexplique la recette 16.2, page 368.) Linvite est affiche par
linterprteur de commandes. Cest vous de saisir le reste de la ligne. De manire similaire, la dernire ligne de ces exemples est souvent une invite ( nouveau un $) afin de
montrer que lexcution de la commande est termine et que le contrle est revenu au
shell.
Le symbole dise (#) pose plus de problmes. Dans de nombreux fichiers Unix ou Linux,
y compris les scripts du shell bash, ce symbole dnote le dbut dun commentaire et nos
exemples lemploient ainsi. Mais, dans linvite de bash ( la place de $), # signifie que
vous avez ouvert une session en tant que root. Puisquun seul de nos exemples excute
ses commandes en tant que root, vous ne devriez pas tre trop perturb, mais il est important que vous le sachiez.
Lorsque la chane dinvite est absente dun exemple, nous montrons en ralit le contenu dun script shell. Pour quelques exemples longs, nous numrotons les lignes du
script, mais ces numros ne font pas partie du script lui-mme.
Parfois, nous montrons un exemple sous forme dun journal de session ou dune suite
de commandes. Nous pouvons galement utiliser la commande cat avec un ou plusieurs fichiers afin de vous rvler le contenu du script et/ou des fichiers de donnes utiliss dans lexemple ou dans le rsultat dune opration.
$ cat fichiers_donnees
static en-tete ligne1
static en-tete ligne2
1 toto
2 titi
3 tata

De nombreux scripts et fonctions plus labors sont galement disponibles en tlchargement. Pour plus de dtails, reportez-vous la section Votre avis, page xxi. Nous avons
dcid dutiliser #!/usr/bin/env bash avec ces exemples car cette dclaration est plus portable que #!/bin/bash, que vous pourrez rencontrer sur Linux ou sur un Mac. Pour plus
dinformations, consultez la recette 15.1, page 334.
Vous pourrez galement remarquer la ligne suivante dans certains exemples de code :
# bash Le livre de recettes : nom_extrait

Cela signifie que le code, en version amricaine, est disponible en tlchargement sur
le site mis en place par les auteurs pour ce livre (http://www.bashcookbook.com). Sa version francise se trouve sur le site http://www.oreilly.fr/catalogue/2841774473. Le tlchargement (.tgz ou .zip) est document, mais vous trouverez le code dans les fichiers
au format ./chXX/nom_extrait, o chXX correspond au chapitre et nom_extrait au nom du
fichier.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Prface

xix

Utilisation inefficace de cat


Certains utilisateurs Unix aiment reprer les points dinefficacit dans le code des
autres. En gnral, cette critique est apprcie lorsquelle est donne de manire constructive.
Le cas le plus courant est probablement lutilisation inefficace de cat , signal lorsque
quelquun excute cat fichier | grep toto la place de grep toto fichier. Dans ce cas,
cat est inutile et implique un surcot puisque la commande sexcute dans un sous-shell.
Un autre cas frquent est cat fichier | tr '[A-Z]' '[a-z]' la place de tr '[A-Z]'
'[a-z]' < fichier. Parfois, lemploi de cat peut mme provoquer le dysfonctionnement
dun script (voir la recette 19.8, page 493).
Mais, une utilisation superflue de cat sert parfois un objectif. Elle peut reprsenter un
emplacement dans un tube que dautres commandes remplaceront par la suite (peuttre mme cat -n). Dautre part, en plaant le fichier sur le ct gauche dune commande, votre attention soriente plus facilement vers cette partie du code. Ce ne sera pas le
cas si le fichier se trouve derrire un symbole < lextrmit droite de la page.
Mme si nous approuvons lefficacit, ainsi que la ncessit de la rechercher, elle nest
plus aussi essentielle quelle a pu ltre. Cependant, nous ne militons pas en faveur de la
ngligence ou de lexplosion de code. Nous disons simplement que la rapidit des processeurs nest pas vraiment en dclin. Si vous aimez utiliser cat, nhsitez donc pas.

Note propos de Perl


Nous vitons volontairement lemploi de Perl dans nos solutions, autant que possible,
mme si, dans certains cas, il serait le bienvenu. Perl fait dj lobjet dune description
dtaille dans dautres ouvrages, bien plus que nous ne pourrions le faire ici. Dautre
part, Perl savre gnralement plus long, avec un surcot plus important, que nos solutions. Il existe galement une mince frontire entre lcriture de scripts shell et de
scripts Perl ; le sujet de ce livre est lcriture de scripts shell.
Les scripts shell servent combiner des programmes Unix, tandis que Perl inclut de
nombreuses fonctionnalits des programmes Unix externes dans le langage lui-mme.
Il est ainsi plus efficace et, dune certaine manire, plus portable. Cependant, il est galement diffrent et complique lexcution efficace des programmes externes dont vous
avez besoin.
Le choix de loutil employer est souvent plus guid par ses connaissances de loutil que
par toute autre raison. En revanche, lobjectif est toujours de raliser le travail ; le choix
de loutil est secondaire. Nous vous montrerons plusieurs manires de raliser certaines
oprations avec bash et des outils connexes. Lorsque votre but sera de mener bien votre
travail, vous devrez choisir les outils utiliser.

Autres ressources

Perl Cookbook, 3e dition, Nathan Torkington et Tom Christiansen (OReilly Media) ;

Programmation en Perl, 3e dition, Larry Wall et autres (ditions OReilly) ;

De lart de programmer en Perl, Damian Conway (ditions OReilly) ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

xx

Prface

Matrise des expressions rgulires, 2e dition, Jeffrey E. F. Friedl (ditions OReilly) ;

Le shell Bash, 3e dition, Cameron Newham (ditions OReilly) ;

Introduction aux scripts shell, Nelson H.F. Beebe et Arnold Robbins (ditions
OReilly).

Conventions typographiques
Les conventions typographiques sont les suivantes :
Menu

Indique des intituls, des options et des boutons de menus, ainsi que des touches
du clavier, comme Alt et Ctrl.
Italique
Dsigne des termes nouveaux, des URL, des adresses lectroniques, des noms de
fichiers, des extensions de fichiers, des noms de chemins, des rpertoires et des utilitaires Unix.
Chasse fixe
Cette police est utilise pour les commandes, les options, les variables, les attributs,
les fonctions, les types, les classes, les espaces de noms, les mthodes, les modules,
les proprits, les paramtres, les valeurs, les objets, les vnements, les gestionnaires dvnements, les balises XML, les balises HTML, les macros, le contenu des
fichiers et la sortie des commandes.
Chasse fixe gras
Signifie lutilisateur de saisir littralement des commandes ou du texte.
Chasse fixe italique
Montre que du texte doit tre remplac par des valeurs saisies par lutilisateur.
Cette icne signifie un conseil, une suggestion ou une note gnrale.

Ce pige vous met en garde.

Utiliser les exemples de code


Ce livre a comme objectif de vous aider. En gnral, vous pourrez utiliser les exemples
de code sans restriction dans vos pages web et vos conceptions. Vous naurez pas besoin
de contacter OReilly pour une autorisation, moins que vous ne vouliez reproduire
des portions significatives de code. La conception dun programme reprenant plusieurs
extraits de code de cet ouvrage ne requiert aucune autorisation. Par contre, la vente et
la distribution dun CD-ROM dexemples provenant des ouvrages OReilly en ncessitent une. Rpondre une question en citant le livre et les exemples de code ne requi[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Prface

xxi

rent pas de permission. Par contre intgrer une quantit significative dexemples de
code extraits de ce livre, dans la documentation de vos produits en ncessite une.
Nous apprcions, sans limposer, lattribution de lorigine de ce code. Une attribution
comprend gnralement le titre, lauteur, lditeur et le numro ISBN. Par exemple,
bash Le livre de recettes, de Carl Albing, JP Vossen et Cameron Newham. Copyright
2007 ditions OReilly, 2-84177-447-3 .
Si vous pensez que lutilisation que vous avez faite de ce code sort des limites dune utilisation raisonnable ou du cadre de lautorisation ci-dessus, nhsitez pas nous contacter ladresse editorial@oreilly.fr.

Votre avis
Adressez vos commentaires et questions sur ce livre lditeur :
ditions OReilly
18 rue Sguier
75006 Paris
Une page web existe pour ce livre, o nous donnons les exemples, une liste derrata et
quelques informations supplmentaires, ladresse :
http://www.oreilly.fr/catalogue/2841774473
Vous trouverez galement des informations sur cet ouvrage, des exemples de code, des
errata, des liens, la documentation de bash et bien dautres complments sur le site cr
par les auteurs (en anglais) :
http://www.bashcookbook.com
Pour donner vos commentaires ou poser des questions techniques sur ce livre, envoyez
un courriel :
editorial@oreilly.com
Pour plus dinformations sur les ouvrages, confrences, logiciels, les centres de ressources et le rseau OReilly, rendez-vous sur le site web OReilly ladresse :
http://www.oreilly.com et http://www.oreilly.fr

Remerciements
Merci la GNU Software Foundation et Brian Fox pour avoir crit bash. Merci galement Chet Ramey, qui assure le dveloppement de bash depuis la version 1.14 au milieu des annes 90. Nous lui sommes reconnaissants davoir rpondu nos questions et
davoir relu une version prliminaire de ce livre.

Relecteurs
Un grand merci nos relecteurs : Yves Eynard, Chet Ramey, William Shotts, Ryan Waldron et Michael Wang. Leurs commentaires, leurs suggestions et, dans certains cas, leurs
solutions alternatives nous ont t indispensables. Ils ont galement repr nos erreurs
et, de manire gnrale, amlior cet ouvrage. Les erreurs que vous pourriez trouver
nous sont dues.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

xxii

Prface

OReilly
Nous voulons remercier toute lquipe de OReilly, notamment Mike Loukides, Derek
Di Matteo et Laurel Ruma.

Des auteurs
Carl
Lcriture dun livre nest jamais un effort totalement solitaire. Merci JP et Cameron
davoir travaill avec moi sur ce projet. Nos talents complmentaires et nos disponibilits respectives ont permis dcrire un livre plus abouti. Je voudrais galement remercier
JP pour nous avoir fourni une certaine infrastructure matrielle. Merci Mike pour
avoir accept ma proposition de ce livre sur bash, de mavoir mis en contact avec JP et
Cameron qui avaient un projet similaire, de nous avoir pouss lorsque nous tions bloqus et de nous avoir guids lorsque nous devenions fous. Son assistance permanente et
ses conseils techniques ont t trs apprcis. Ma femme et mes enfants mont patiemment soutenu tout au long de ce projet, en mencourageant, en me motivant et en me
laissant du temps et de la place pour travailler. Je les remercie du fond du cur.
Outre la rdaction de ce livre, un travail de recherche et de prparation a t ncessaire.
Je suis particulirement redevable Dr. Ralph Bjork qui ma initi Unix, bien avant
que quiconque en ait entendu parler. Sa perspicacit, sa prvoyance et ses conseils mont
t bnfiques bien plus longtemps que je ne laurais imagin.
Je ddie ce livre mes parents, Hank et Betty, qui mont apport toutes les meilleures
choses quils avaient moffrir, comme leur prsence, la foi chrtienne, lamour, une excellente ducation, une place dans la vie et tout ce que lon souhaite pour ses propres
enfants. Je ne pourrais jamais les remercier assez.

JP
Merci Cameron pour avoir crit Le shell bash. Son livre ma normment appris et a
t ma premire rfrence lorsque jai dbut ce projet. Merci Carl pour tout son travail, sans lequel il aurait fallu quatre fois plus de temps pour un rsultat infrieur. Je
voudrais remercier Mike davoir accept ce projet, de lavoir aid avancer et davoir
propos Carl de nous rejoindre. Merci galement Carl et Mike pour leur patience
quant mes problmes existentiels et de planning.
Je ddie ce livre Papa, qui en aurait t trs content. Il ma toujours dit que les deux
dcisions les plus importantes sont ce que lon fait et avec qui lon se marie. En y rflchissant, je pense avoir plutt bien russi. Cet ouvrage est donc galement ddi Karen, pour son incroyable soutien, patience et comprhension pendant ce processus plus
long que prvu et sans qui les ordinateurs ne seraient pas aussi amusants. Enfin, merci
Kate et Sam, qui ont tellement contribu rsoudre mes problmes dorganisation.

Cameron
Jaimerais remercier JP et Carl pour leur incroyable travail, sans lequel ce livre nexisterait probablement pas. Merci galement JP pour avoir mis lide dun tel livre sur
bash ; je suis certain quil le regrette parfois, face aux longues heures passes devant le clavier, mais quil est fier dy avoir particip. Enfin, je voudrais nouveau remercier Adam.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1
Dbuter avec bash

Quest-ce quun shell et pourquoi faudrait-il sy intresser ?


Tout systme dexploitation rcent (postrieur 1970) propose une forme dinterface
utilisateur, cest--dire un mcanisme permettant dindiquer les commandes excuter.
Dans les premiers systmes dexploitation, cette interface de commande tait intgre et
il nexistait quune seule manire de converser avec lordinateur. Par ailleurs, linterface
ne permettait dexcuter que des commandes, car ctait alors lunique rle de lordinateur.
Le systme dexploitation Unix a promu la sparation du shell (llment du systme qui
permet de saisir des commandes) de tous les autres composants : le systme dentre/sortie, lordonnanceur, la gestion de la mmoire et tous les autres aspects pris en charge par
le systme dexploitation (dont la plupart des utilisateurs ne veulent pas entendre parler). Linterprteur de commandes ntait quun programme parmi tant dautres. Son
travail tait dexcuter dautres programmes pour le compte des utilisateurs.
Cependant, cette sparation a t le dbut dune rvolution. Le shell ntait quun autre
programme qui sexcutait sur Unix et, si vous naimiez pas celui livr en standard, vous
pouviez crire le vtre. Cest ainsi qu la fin des dix premires annes dexistence
dUnix, au moins deux shells taient en concurrence : le shell Bourne, sh (un descendant
du shell originel de Thomson), et le shell C, csh. La deuxime dcennie dUnix vue
lapparition dautres variantes : le shell Korn (ksh) et la premire version de bash. la
fin de la troisime dcennie, il existait probablement une dizaine de shells diffrents.
Une fois devant votre systme, vous demandez-vous vais-je utiliser csh, bash ou ksh
aujourdhui ? Cest peu probable. Vous utilisez certainement le shell standard livr
avec votre systme Linux (ou BSD, Mac OS X, Solaris, HP/UX). Mais, en sortant linterprteur de commandes du systme dexploitation lui-mme, les dveloppeurs (comme
Brian Fox, le crateur de bash, et Chet Ramey, actuellement responsable de bash) ont
plus de facilit crire de meilleurs shells. Vous pouvez crer un nouveau shell sans toucher au systme dexploitation. Il est ainsi beaucoup plus facile de faire accepter un nouveau shell, puisque les fournisseurs de systmes dexploitation nont pas lintgrer
leur systme. Il suffit de prparer le shell afin quil puisse tre install sur un systme
comme nimporte quel autre programme.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Chapitre 1 Dbuter avec bash

Mais, pourquoi faire autant dhistoires pour un programme qui prend simplement des
commandes et les excute ? Effectivement, si le shell ne vous permettait que de saisir
des commandes, il ne serait gure intressant. Cependant, deux facteurs ont t prdominants dans lvolution du shell Unix : la facilit dutilisation et la programmation. Il
en a rsult un shell moderne qui offre de nombreuses fonctionnalits en plus daccepter des commandes.
Les shells modernes sont trs pratiques. Par exemple, ils se souviennent des commandes
saisies et vous permettent de les rutiliser et de les modifier. Ils vous permettent galement de dfinir vos propres abrviations de commandes, des raccourcis et dautres fonctionnalits. Pour un utilisateur expriment, la saisie de commandes (cest--dire avec
les raccourcis, les alias et la compltion) est beaucoup plus efficace et rapide que le dplacement dicnes au sein dune interface graphique.
Outre leur simple commodit, les shells sont programmables. Certaines suites de commandes sont invoques trs souvent. Ds que vous effectuez une opration plus dune
fois, vous devez vous demander puis-je crire un programme qui fasse cela ma
place ? La rponse est oui. Un shell est aussi un langage de programmation spcifiquement conu pour oprer avec les commandes du systme de votre ordinateur. Par consquent, si vous souhaitez gnrer un millier de fichiers MP3 partir de fichiers WAV,
vous pouvez crire un programme shell (ou un script shell) qui le fera. Si vous souhaitez
compresser tous les fichiers de journalisation de votre systme, vous pouvez crire un
script shell qui ralisera ce travail. Ds quune tche devient rptitive, vous devez essayer de lautomatiser en crivant un script shell. Il existe plusieurs langages de scripts
puissants, comme Perl, Python et Ruby, mais linterprteur de commandes dUnix
(quelle que soit la variante du shell que vous utilisez) est un bon point de dpart. En
effet, vous savez dj saisir des commandes, alors pourquoi compliquer les choses ?

Intrt de bash
Si ce livre sarticule autour de bash et non dun autre shell, cest que bash est largement
disponible. Il nest pas le plus rcent, sans doute pas le plus fantaisiste ni le plus puissant
(quoi quil ne doit pas en tre loin) et nest pas le seul tre distribu comme logiciel
Open Source, mais il est omniprsent.
Les raisons en sont historiques. Les premiers shells taient plutt de bons outils de programmation, mais ils taient peu pratiques pour les utilisateurs. Le shell C a amlior
la facilit dutilisation, comme la possibilit de rpter une commande dj saisie, mais
faisait un pitre langage de programmation. Le shell Korn, sorti ensuite (au dbut des
annes 80), a amlior la facilit dutilisation et le langage de programmation et semblait promis un grand avenir. Malheureusement, ksh ntait pas initialement un logiciel Open Source ; il tait un produit propritaire, donc difficile fournir avec un systme
dexploitation gratuit comme Linux. Sa licence a t modifie en 2000, puis nouveau
en 2005.
la fin des annes 80, la communaut Unix a dcid que la standardisation tait une
bonne chose et les groupes de travail POSIX (sous lgide de lIEEE) ont t forms.
POSIX a normalis les bibliothques et les utilitaires Unix, en particulier le shell. Linterprteur de commandes standard tait principalement bas sur la version de 1988 du
shell Korn, avec certaines caractristiques du shell C et quelques innovations. bash a d-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Dbuter avec bash

marr au sein du projet GNU, dont le but tait de crer un systme POSIX complet et
donc un shell POSIX.
bash offrait les possibilits indispensables aux programmeurs shell, ainsi que la commodit souhaite par les utilisateurs de la ligne de commande. lorigine, il a t conu
comme une alternative au shell Korn, mais avec limportance prise par le mouvement
du logiciel libre et la large adoption de Linux, bash a rapidement clips ksh.
Cest ainsi que bash est devenu linterprteur de commandes par dfaut de toutes les distributions Linux que nous connaissons (il existe une centaine de distributions Linux et
il est probable que quelques-unes choisissent un autre shell par dfaut), ainsi que sur
Mac OS X. Il est galement disponible pour tous les autres systmes dexploitation Unix,
notamment BSD et Solaris. Dans les rares cas o bash nest pas livr avec le systme, son
installation reste simple. Il est mme disponible pour Windows (via Cygwin). bash est
la fois un langage de programmation puissant et une bonne interface utilisateur. Vous
naurez mme pas sacrifier des raccourcis clavier pour obtenir des fonctions de programmation labores.
En vous formant bash, vous ne pouvez pas vous tromper. Les shells par dfaut les plus
rpandus sont lancien shell Bourne et bash, dont la compatibilit avec le premier est
excellente. Lun de ces interprteurs de commandes est sans aucun doute prsent sur
tout systme dexploitation Unix, ou assimil, moderne. De plus, comme nous lavons
prcis, si bash est absent de votre machine, rien ne vous empche de linstaller. Cependant, il existe dautres shells. Dans lesprit du logiciel libre, les auteurs et les responsables
de tous ces shells partagent leurs ides. Si vous consultez les rapports de modification de
bash, vous constaterez que de nombreuses caractristiques ont t ajoutes ou ajustes
afin dassurer une compatibilit avec un autre shell. Cependant, la plupart des utilisateurs sen moquent. Ils prennent ce qui existe et sen contentent. Par consquent, si cela
vous intresse, vous pouvez tudier dautres shells. Il existe de nombreuses alternatives
dignes dintrt et vous pourriez en prfrer certaines, mme si elles ne seront probablement pas aussi rpandues que bash.

Le shell bash
bash est un shell, cest--dire un interprteur de commandes. Son principal objectif,
comme celui de nimporte quel shell, est de vous permettre dinteragir avec le systme
dexploitation de lordinateur afin daccomplir vos tches. En gnral, cela implique le
lancement de programmes. Le shell prend donc les commandes saisies, dtermine les
programmes qui doivent tre excuts et les lance pour vous. Certaines tches demandent lexcution dune suite dactions rcurrente ou trs complexe, voire les deux. La
programmation shell, ou lcriture de scripts shell, vous permet dautomatiser ces tches, pour plus de facilit dutilisation, de fiabilit et de reproductibilit.
Si bash est nouveau pour vous, nous commencerons par certains fondamentaux. Si vous
avez dj utilis Unix ou Linux, vous avez probablement rencontr bash, mais peut-tre
sans le savoir. bash est essentiellement un langage dexcution de commandes et celles
que vous avez dj pu saisir, comme ls, cd, grep ou cat, sont, en un sens, des commandes
bash. Parmi ces commandes, certaines sont intgres bash lui-mme, tandis que
dautres sont des programmes spars. Pour le moment, cette diffrence nest pas importante.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Chapitre 1 Dbuter avec bash

Nous terminerons ce chapitre en expliquant comment obtenir bash. La plupart des systmes sont livrs avec une version de bash installe, mais ce nest pas le cas de tous.
Mme si votre systme vient avec bash, il est toujours bon de savoir comment lobtenir
et linstaller. De nouvelles versions, offrant de nouvelles fonctionnalits, sortent de
temps autre.
Si vous utilisez dj bash et en avez une certaine habitude, vous pouvez aller directement au chapitre 2. Vous ntes pas oblig de lire ce livre du dbut la fin. Si vous consultez les recettes des chapitres centraux, vous verrez de quoi bash est rellement
capable. Mais, commenons par le dbut.

1.1. Comprendre linvite de commandes


Problme
Vous voulez savoir ce que signifient tous ces symboles de ponctuation.

Solution
Tous les interprteurs de commandes possdent une forme dinvite qui vous signale que
le shell est prt accepter vos ordres. Laspect de linvite dpend de nombreux facteurs,
en particulier du type et de la version du systme dexploitation, du type et de la version
du shell, de la distribution et de sa configuration. Dans la famille des shells Bourne, le
symbole $ la fin de linvite signifie gnralement que vous avez ouvert une session en
tant quutilisateur normal, tandis que le symbole # signifie que vous tes le super-utilisateur (root). Le compte root est ladministrateur du systme et quivaut au compte Systme de Windows (plus puissant que le compte Administrateur) ou au compte Superviseur
de Netware. root est tout-puissant et peut faire tout ce quil veut sur un systme Unix ou
Linux classique.
Les invites par dfaut affichent souvent le chemin du rpertoire courant, mme si elles
peuvent labrger. Le symbole ~ signifie que le rpertoire de travail est votre rpertoire
personnel. Certaines invites par dfaut peuvent galement afficher votre nom dutilisateur et le nom de la machine sur laquelle vous tes connect. Si, pour le moment, cela
vous semble idiot, vous changerez davis lorsque vous serez connect cinq machines
sous des noms potentiellement diffrents.
Voici une invite Linux classique, pour lutilisateur jp sur la machine adams, actuellement dans son rpertoire personnel. Le symbole $ final indique quil sagit dun utilisateur normal, non de root.
jp@adams:~$

En passant dans le rpertoire /tmp, voici ce que devient linvite. Vous remarquerez que
~, qui signifie en ralit /home/jp, a t remplac par /tmp.
jp@adams:/tmp$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.2. Afficher son emplacement

Discussion
Linvite du shell est un lment prdominant de la ligne de commande et ses possibilits
de personnalisation sont nombreuses. Pour le moment, vous devez simplement savoir
comment linterprter. Bien entendu, votre invite par dfaut peut tre diffrente, mais
vous devez dj tre en mesure de la comprendre, au moins partiellement.
Certains systmes Unix ou Linux offrent accs la puissance de root par le biais de commandes comme su et sudo. Parfois, root nest pas rellement tout-puissant, par exemple
lorsque le systme intgre une politique des accs (MAC mandatory access control),
comme SELinux de la NSA.

Voir aussi

la recette 1.2, Afficher son emplacement, page 5 ;

la recette 14.19, Utiliser sudo de manire plus sre, page 318 ;

la recette 16.2, Personnaliser linvite, page 368 ;

la recette 17.15, Utiliser sudo avec un groupe de commandes, page 454.

1.2. Afficher son emplacement


Problme
Vous ntes pas certain de votre rpertoire de travail et linvite par dfaut nest daucune
aide.

Solution
Utilisez la commande interne pwd ou dfinissez une invite plus utile (voir la recette 16.2,
page 368). Par exemple :
bash-2.03$ pwd
/tmp
bash-2.03$ export PS1='[\u@\h \w]$ '
[jp@solaris8 /tmp]$

Discussion
pwd signifie print working directory (afficher le rpertoire de travail) et accepte deux arguments. -L, loption par dfaut, affiche votre chemin logique. -P affiche votre emplacement physique, qui peut tre diffrent du chemin logique si vous avez suivi un lien
symbolique.
bash-2.03$ pwd
/tmp/rep2

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Chapitre 1 Dbuter avec bash


bash-2.03$ pwd -L
/tmp/rep2
bash-2.03$ pwd -P
/tmp/rep1

Voir aussi

la recette 16.2, Personnaliser linvite, page 368.

1.3. Chercher et excuter des commandes


Problme
Vous voulez trouver et excuter une commande prcise sous bash.

Solution
Essayez les commandes type, which, apropos, locate, slocate, find et ls.

Discussion
bash gre une liste des rpertoires dans lesquels il doit rechercher les commandes. Cette
liste est place dans la variable denvironnement $PATH. La commande type interne
bash cherche dans votre environnement (y compris les alias, les mots-cls, les fonctions,
les commandes internes et les fichiers dans $PATH) les commandes excutables correspondant ses arguments et affiche le type et lemplacement de celles trouves. Parmi
tous ces arguments, loption -a permet dafficher toutes les correspondances et pas seulement la premire. La commande which est similaire, mais sa recherche se fait uniquement dans la variable $PATH (et les alias de csh). Elle peut tre diffrente dun systme
lautre (il sagit souvent dun script csh sur BSD et dun binaire sur Linux), mais elle accepte gnralement loption -a, tout comme type. Vous pouvez vous en servir lorsque
vous connaissez le nom de la commande et souhaitez connatre son emplacement prcis, ou bien pour savoir si elle existe sur lordinateur. Par exemple :
$ type which
which is hashed (/usr/bin/which)
$ type ls
ls is aliased to `ls -F -h'
$ type -a ls
ls is aliased to `ls -F -h'
ls is /bin/ls
$ which which
/usr/bin/which

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.3. Chercher et excuter des commandes

Pratiquement toutes les commandes disposent dune aide sur leur utilisation. En gnral, il existe une documentation en ligne sous forme de pages de manuel (manpages).
Pour les consulter, utilisez la commande man. Par exemple, man ls affiche la documentation de la commande ls. De nombreux programmes offrent galement une aide intgre laquelle on accde laide dun argument, comme -h ou --help. Certains
programmes, en particulier sur dautres systmes dexploitation, affichent une aide lorsque vous ne passez aucun argument. Cest galement le cas de quelques commandes
Unix, mais elles sont rares. La raison provient de lutilisation des commandes Unix dans
les tubes. Nous y reviendrons plus loin. Mais, que pouvez-vous faire si vous ne connaissez pas ou si vous avez oubli le nom de la commande dont vous avez besoin ?
apropos recherche dans les intituls et les descriptions des pages de manuel les expressions rgulires passes en argument. Elle savre incroyablement utile lorsque vous
avez oubli le nom dune commande. Elle quivaut man -k.
$ apropos music
cms (4) - Creative Music System device driver
$ man -k music
cms (4) - Creative Music System device driver

locate et slocate consultent les bases de donnes du systme (gnralement compiles et


actualises par une tche cron) pour trouver, quasi instantanment, des fichiers ou des
commandes. Lemplacement des bases de donnes, les informations indexes et la frquence des mises jour peuvent varier dun systme lautre. Pour plus de dtails, consultez les pages de manuel de votre systme. Outre les noms de fichiers et les chemins,
slocate stocke des informations dautorisation afin de ne pas prsenter lutilisateur des
programmes auxquels il na pas accs. Sur la plupart des systmes Linux, locate est un
lien symbolique vers slocate. Sur dautres systmes, ces programmes peuvent tre distincts ou slocate peut ne pas exister.
$ locate apropos
/usr/biSOpropos
/usr/share/man/de/man1/apropos.1.gz
/usr/share/man/es/man1/apropos.1.gz
/usr/share/man/it/man1/apropos.1.gz
/usr/share/man/ja/man1/apropos.1.gz
/usr/share/man/man1/apropos.1.gz

Pour plus dinformations sur la commande find, consultez le chapitre 9.


Enfin, vous pouvez galement essayer la commande ls. Noubliez pas que si la commande recherche se trouve dans votre rpertoire de travail, vous devez la prfixer par ./
puisque, pour des raisons de scurit, le rpertoire courant ne se trouve gnralement
pas dans $PATH (voir les recettes 14.3, page 294, et 14.10, page 303).

Voir aussi

help type ;

man which ;

man apropos ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Chapitre 1 Dbuter avec bash

man locate ;

man slocate ;

man find ;

man ls ;

le chapitre 9, Rechercher des fichiers avec find, locate et slocate, page 191 ;

la recette 4.1, Lancer nimporte quel excutable, page 71 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303.

1.4. Obtenir des informations sur des fichiers


Problme
Vous avez besoin dinformations complmentaires sur un fichier, comme sa nature, son
propritaire, ses droits dexcution, le nombre de liens physiques quil possde ou la
date de dernier accs ou de dernire modification.

Solution
Utilisez les commandes ls, stat, file ou find.
$ touch /tmp/fichier

$ ls /tmp/fichier
/tmp/fichier
$ ls -l /tmp/fichier
-rw-r--r-- 1 jp jp 0 2007-06-19 15:03 /tmp/fichier

$ stat /tmp/fichier
File: "/tmp/fichier"
Size: 0
Blocks: 0
IO Block: 4096
fichier rgulier
Device: 303h/771d Inode: 2310201
Links: 1
Access: (0644/-rw-r--r--) Uid: ( 501/
jp) Gid: ( 501/
jp)
Access: 2007-06-19 14:23:10.000000000 +0200
Modify: 2007-06-19 14:23:10.000000000 +0200
Change: 2007-06-19 14:23:10.000000000 +0200

$ file /tmp/fichier
/tmp/fichier: empty
$ file -b /tmp/fichier
empty

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.4. Obtenir des informations sur des fichiers

$ echo '#!/bin/bash -' > /tmp/fichier

$ file /tmp/fichier
/tmp/fichier: Bourne-Again shell script text executable
$ file -b /tmp/fichier
Bourne-Again shell script text executable

Le chapitre 9 reviendra en dtail sur la commande find.

Discussion
La commande ls affiche uniquement les noms de fichiers, tandis que ls -l fournit des
dtails supplmentaires sur chaque fichier. ls accepte de nombreuses options ; consultez
sa page de manuel sur votre systme pour les connatre. Voici quelques-unes des options
intressantes :
-a
Ne pas masquer les fichiers commenant par . (point).
-F
Afficher le type du fichier en ajoutant lun des symboles de type suivant : /*@%=|.
-l
Prsenter une liste dtaille.
-L
Rvler les informations sur le fichier li et non sur le lien symbolique lui-mme.
-Q
Encadrer les noms de fichiers avec des guillemets (extension GNU, non reconnue
par tous les systmes).
-r
Inverser lordre de tri.
-R
Parcourir les sous-rpertoires.
-S
Trier daprs la taille de fichier.
-1
Utiliser le format court, mais avec un fichier par ligne.
Avec loption -F, une barre oblique (/) dsigne un rpertoire, un astrisque (*) indique
que le fichier est excutable, un symbole arobase (@) dsigne un lien symbolique, un signe gal (=) dsigne une socket et un tube (|) les FIFO (first-in, first-out).
stat, file et find acceptent de nombreux paramtres qui rglent le format de la sortie ;
consultez les pages de manuel de votre systme pour les connatre. Par exemple, les options suivantes produisent une sortie similaire celle de ls -l :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

10

Chapitre 1 Dbuter avec bash


$ ls -l /tmp/fichier
-rw-r--r-- 1 jp jp 0 2007-06-19 15:03 /tmp/fichier
$ stat -c'%A %h %U %G %s %y %n' /tmp/fichier
-rw-r--r-- 1 jp jp 14 2007-06-19 14:26:32.000000000 +0200 /tmp/fichier
$ find /tmp/ -name fichier -printf '%m %n %u %g %t %p'
644 1 jp jp Tue Jun 19 14:26:32 2007 /tmp/fichier

Ces outils ne sont pas disponibles sur tous les systmes dexploitation, ni dans certaines
versions. Par exemple, la commande stat nexiste pas, par dfaut, sur Solaris.
Vous devez savoir que les rpertoires ne sont rien dautres que des fichiers traits de manire particulire par le systme dexploitation. Les commandes prcdentes fonctionnent donc galement sur les rpertoires, mme si vous devez parfois les modifier pour
obtenir ce que vous souhaitez. Par exemple, utilisez ls -d pour afficher les informations
concernant un rpertoire, la place de ls seule qui affiche le contenu dun rpertoire.

Voir aussi

man ls ;

man stat ;

man file ;

man find ;

le chapitre 9, Rechercher des fichiers avec find, locate et slocate, page 191.

1.5. Afficher tous les fichiers cachs


Problme
Vous voulez voir uniquement les fichiers cachs (avec un point) dun rpertoire afin de
modifier un fichier dont vous avez oubli le nom ou pour supprimer des fichiers obsoltes. ls -a affiche tous les fichiers, y compris ceux normalement cachs, mais elle est
trop prolixe et ls -a .* ne vous convient pas.

Solution
Utilisez ls -d combine vos autres critres.
ls -d .*
ls -d .b*
ls -d .[!.]*

Vous pouvez galement adapter la commande de manire retirer . et .. de la liste.


$ grep -l 'PATH' ~/.[!.]*
/home/jp/.bash_history
/home/jp/.bash_profile

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.5. Afficher tous les fichiers cachs

11

Discussion
En raison de la manire dont le shell traite les caractres gnriques, la combinaison .*
ne se comporte pas forcment comme vous le supposez. Lexpansion des noms de fichiers,
ou globalisation (globbing), considre toute chane contenant les caractres *, ? ou [ comme un motif et la remplace par une liste alphabtique des noms de fichiers qui correspondent ce motif. * correspond nimporte quelle chane, y compris la chane vide,
tandis que ? quivaut un seul caractre. Les caractres placs entre [ et ] dfinissent
une liste ou une plage de caractres, chacun devant correspondre. Il existe galement
dautres oprateurs de correspondance de motifs, mais nous ne les prsenterons pas
dans ce chapitre (voir les sections Caractres pour la correspondance de motifs, page 546, et
Oprateurs pour la correspondance de motifs tendue extglob, page 547). Ainsi, *.txt signifie tout fichier se terminant par .txt, tandis que *txt reprsente tout fichier se terminant
par txt (sans point). f?o correspond foo ou fao, mais pas fooo. Vous pourriez donc
penser que .* correspond tout fichier qui commence par un point.
Malheureusement, lexpansion de .* inclut . et .., qui sont donc tous deux affichs. Au
lieu dobtenir uniquement les fichiers commenant par un point dans le rpertoire de
travail, vous obtenez galement ces fichiers, tous les fichiers et rpertoires du rpertoire
courant (.), tous les fichiers et rpertoires du rpertoire parent (..), ainsi que les noms et
le contenu de tous les sous-rpertoires du rpertoire de travail qui commencent par un
point. Cest, pour le moins, assez perturbant.
Vous pouvez essayer la mme commande ls avec et sans loption -d, puis echo .*. Cette
commande echo affiche simplement le rsultat de lexpansion de .* par le shell. Essayez
galement echo .[!.]*.
.[!.]* est un motif dans lequel [ ] prcise la liste des caractres employs dans la correspondance, mais le symbole ! du dbut inverse le rle de la liste. Nous recherchons
donc tout ce qui commence par un point, suivi de tout caractre autre quun point, suivi
dun nombre quelconque de caractres. Vous pouvez galement employer ^ pour inverser une classe de caractres, mais ! fait partie des spcifications de POSIX et est donc plus
portable.
.[!.]* ne trouvera pas un fichier nomm ..toto. Vous pouvez ajouter
quelque chose comme .??* pour trouver les correspondances avec tout
ce qui commence par un point et qui contient au moins trois caractres. Mais, ls -d .[!.]* .??* affiche alors deux fois tout ce qui correspond aux deux motifs. Vous pouvez galement utiliser .??* seul, mais
les fichiers comme .a sont alors oublis. La solution dpend de vos
besoins et de votre environnement. Il nexiste pas de rponse adapte
tous les cas.

[05/03/08]

bash Le livre de recettes

$ ls -a
.
..

..toto
.a

$ ls -d .[!.]*
.a

.fichier_point_normal

.fichier_point_normal
fichier_normal

Elodie FRITSCH <elodie.fritsch@total.com>

12

Chapitre 1 Dbuter avec bash

$ ls -d .??*
..toto

.fichier_point_normal

..toto
.a
fichier_point_normal

.fichier_point_normal

$ ls -d .[!.]* .??* | sort -u


..toto
.a
.fichier_point_normal

echo * peut remplacer ls si cette commande est corrompue ou indisponible. Cela fonctionne car le shell transforme * en tout le contenu du
rpertoire courant, cest--dire une liste similaire celle obtenue avec
ls.

Voir aussi

man ls ;

http://www.gnu.org/software/coreutils/faq/#ls-_002da-_002a-does-not-list-dot-files ;

la section 2.11 de http://www.faqs.org/faqs/unix-faq/faq/part2 ;

la section Caractres pour la correspondance de motifs, page 546 ;

la section Oprateurs pour la correspondance de motifs tendue extglob, page 547.

1.6. Protger la ligne de commande


Problme
Vous souhaitez disposer dune rgle gnrale pour protger la ligne de commande.

Solution
Entourez une chane par des apostrophes, sauf si elle contient des lments que le shell
doit interprter.

Discussion
Le texte non protg, tout comme celui plac entre guillemets, est assujetti lexpansion
et la substitution par le shell. Prenons les exemples suivants :
$ echo Un caf vaut $5?!
Un caf vaut ?!
$ echo "Un caf vaut $5?!"
bash: !": event not found

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.6. Protger la ligne de commande

13

$ echo 'Un caf vaut $5?!'


Un caf vaut $5?!

Dans le premier exemple, $5 est trait comme une variable, mais, puisquelle nexiste
pas, elle est fixe une valeur nulle. Cest galement le cas dans le deuxime exemple,
mais nous nallons mme pas jusque-l car !" est trait comme une substitution de lhistorique, qui choue car elle ne correspond rien. Le troisime exemple fonctionne comme voulu.
Pour combiner des expansions du shell et des chanes littrales, vous pouvez vous servir
de caractre dchappement du shell (\) ou modifier la protection. Le point dexclamation est un cas particulier car la barre oblique inverse qui prcde nest pas retire. Vous
pouvez contourner ce problme laide dapostrophes ou en ajoutant une espace la
fin.
$ echo 'Un caf vaut $5 pour' "$USER" '?!'
Un caf vaut $5 pour jp ?!
$ echo "Un caf vaut \$5 pour $USER?\!"
Un caf vaut $5 pour jp?\!
$ echo "Un caf vaut \$5 pour $USER?! "
Un caf vaut $5 pour jp?!

Par ailleurs, vous ne pouvez pas placer une apostrophe lintrieur dune chane entre
apostrophes, mme en utilisant une barre oblique inverse, puisque rien, pas mme la
barre oblique inverse, nest interprt lintrieur des chanes entre apostrophes. Cependant, vous pouvez contourner ce problme en utilisant des guillemets avec chappement ou en chappant une seule apostrophe lextrieur des apostrophes
englobantes.
#
#
$
>

Nous obtenons une invite de poursuite puisque les apostrophes


ne sont pas quilibres.
echo '$USER nachtera pas son caf $5.'
^C

# MAUVAIS.
$ echo "$USER nachtera pas son caf $5."
jp nachtera pas son caf .
# OK.
$ echo "$USER nachtera pas son caf \$5."
jp nachtera pas son caf $5.
# OK.
$ echo 'Je n'\'achterai pas mon caf $5.'
Je nachterai pas mon caf $5.

Voir aussi

le chapitre 5, Variables du shell, page 85, pour tous les dtails sur les variables du
shell et la syntaxe $VAR ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14

Chapitre 1 Dbuter avec bash


le chapitre 18, Rduire la saisie, page 475, pour plus dinformations sur ! et lhistorique des commandes.

1.7. Utiliser ou remplacer des commandes


Problme
Vous voulez remplacer une commande interne par votre propre fonction ou une commande externe et vous devez savoir prcisment la commande excute par votre script
(par exemple, le programme externe /bin/echo ou la commande interne echo). Si vous
avez cr une nouvelle commande, elle peut tre en conf lit avec une commande interne
ou une externe existante.

Solution
Utilisez type et which pour savoir si une commande existe et si elle est interne ou externe.
# type cd
cd is a shell builtin
# type awk
awk is /biSOwk
# which cd
/usr/bin/which: no cd in
(/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin/X11:
/usr/X11R6/bin:/root/bin)
# which awk
/bin/awk

Discussion
Une commande interne fait partie intgrante du shell, tandis quune commande externe est un fichier spar lanc par le shell. Ce fichier peut tre un binaire ou un script
shell, mais il est important de comprendre la diffrence. Premirement, lorsque vous
utilisez une certaine version dun shell, les commandes internes sont toujours disponibles, contrairement aux programmes externes qui peuvent ou non tre installs sur le
systme. Deuximement, si vous donnez lun de vos programmes le nom dune commande interne, vous risquez dtre surpris par le rsultat puisque la commande interne
reste prioritaire (voir la recette 19.4, page 489). Vous pouvez utiliser enable pour activer
et dsactiver des commandes internes, mais nous dconseillons cette solution sauf si
vous tes absolument certain de bien comprendre ce que vous faite. enable -a affiche
toutes les commandes internes et leur tat dactivation.
Avec les commandes internes, les options -h ou --help, qui permettent dobtenir des
informations sur lutilisation dune commande, ne sont gnralement pas disponibles

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.8. Dterminer si le shell est en mode interactif

15

et, si une page de manuel existe, elle fait souvent rfrence celle de bash. Dans ce cas,
la commande interne help peut vous tre utile. Elle affiche une aide sur les commandes
internes du shell.
# help help
help: help [-s] [pattern ...]
Display helpful information about builtin commands. If PATTERN is
specified, gives detailed help on all commands matching PATTERN,
otherwise a list of the builtins is printed. The -s option
restricts the output for each builtin command matching PATTERN to
a short usage synopsis.

Lorsque vous redfinissez une commande interne, utilisez builtin pour viter les boucles. Par exemple :
cd () {
builtin cd "$@"
echo "$OLDPWD --> $PWD"
}

Pour obliger le shell invoquer une commande externe la place dune fonction ou
dune commande interne, qui sont prioritaires, utilisez enable -n, qui dsactive les commandes internes du shell, ou command, qui ignore les fonctions du shell. Par exemple,
pour invoquer le programme test dsign par la variable $PATH la place de la version
interne du shell, saisissez enable -n test, puis excutez test. Pour invoquer la commande ls native la place dune fonction ls que vous auriez pu crer, utilisez command ls.

Voir aussi

man which ;

help help ;

help builtin ;

help command ;

help enable ;

help type ;

la recette 19.4, Nommer un script test , page 489 ;

la section Variables internes, page 510.

1.8. Dterminer si le shell est en mode


interactif
Problme
Vous voulez excuter un certain code uniquement si le shell se trouve (ou ne se trouve
pas) en mode interactif.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16

Chapitre 1 Dbuter avec bash

Solution
Utilisez linstruction case suivante :
#!/usr/bin/env bash
# bash Le livre de recettes : interactive
case "$-" in
*i*) # Code pour le shell interactif.
;;
*)
# Code pour le shell non interactif.
;;
esac

Discussion
La variable $- contient la liste de toutes les options en cours du shell. Si celui-ci fonctionne en mode interactif, elle contiendra i.
Vous pourriez galement rencontrer du code similaire au suivant (il fonctionne parfaitement, mais la solution prcdente est conseille) :
if [ "$PS1" ]; then
echo Ce shell est interactif
else
echo Ce shell n\est pas interactif
fi

Voir aussi

help case ;

help set ;

la recette 6.14, Raliser des branchements multiples, page 137, pour plus dinformations sur linstruction case.

1.9. Faire de bash le shell par dfaut


Problme
Vous utilisez un systme BSD, Solaris ou une autre variante dUnix et bash nest pas le
shell pas dfaut. Vous ne voulez plus lancer bash explicitement, mais en faire votre shell
par dfaut

Solution
Tout dabord, vrifiez que bash est install. Si lexcution de bash --version affiche une
description, alors ce shell est install sur votre systme :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.9. Faire de bash le shell par dfaut

17

$ bash --version
GNU bash, version 3.00.16(1)-release (i386-pc-solaris2.10)
Copyright (C) 2004 Free Software Foundation, Inc.

Si vous nobtenez aucun numro de version, il manque peut-tre un rpertoire dans votre chemin. Sur certains systmes, chsh -l ou cat /etc/shells affiche une liste des
shells valides. Sinon, demandez votre administrateur lemplacement de bash ou sil
peut tre install.
Sous Linux, chsh -l prsente une liste des shells valides, mais, sous BSD, cette commande ouvre un diteur qui permet de modifier la configuration. Loption -l nest pas reconnue dans la version de chsh pour Mac OS X, mais lexcution de chsh ouvre un
diteur pour modifier la configuration et chpass -s shell change de shell.
Si bash est install, utilisez la commande chsh -s pour changer de shell par dfaut. Par
exemple, chsh -s /bin/bash. Si cette commande choue, essayez chsh, passwd -e, passwd -l chpass ou usermod -s /usr/bin/bash. Si vous ne parvenez toujours pas changer
de shell, demandez votre administrateur systme, qui devra peut-tre revoir le fichier
/etc/passwd. Sur la plupart des systmes, il contient des lignes au format suivant :
cam:pK1Z9BCJbzCrBNrkjRUdUiTtFOh/:501:100:Cameron Newham:/home/cam:/bin/bash
cc:kfDKDjfkeDJKJySFgJFWErrElpe/:502:100:Cheshire Cat:/home/cc:/bin/bash

En tant quutilisateur root, vous pouvez modifier le dernier champ des lignes du fichier
des mots de passe afin de prciser le chemin complet du shell choisi. Si votre systme
dispose dune commande vipw, vous devez lutiliser pour prserver la cohrence du fichier des mots de passe.
Certains systmes refuseront tout shell douverture de session qui nest
pas mentionn dans /etc/shells. Si bash nest pas prsent dans ce fichier,
vous devrez demander votre administrateur systme de ly ajouter.

Discussion
Certains systmes dexploitation, principalement les Unix BSD, placent bash dans la partition /usr. Vous devez alors bien rflchir avant de changer le shell de root. Si le systme
rencontre des problmes au dmarrage et si vous devez revoir sa configuration avant
que la partition /usr soit monte, vous vous trouvez dans une situation dlicate : il ny a
aucun shell pour root. Cest pourquoi il est prfrable de ne pas changer le shell par dfaut de root. En revanche, il ny a aucune raison de ne pas affecter bash comme shell par
dfaut pour les comptes classiques. Noubliez pas quil est fortement dconseill dutiliser le compte root, sauf en cas dabsolue ncessit. Servez-vous de votre compte dutilisateur normal lorsque cest possible. Grce aux commandes de type sudo, vous aurez
rarement besoin dun shell root.
Si toutes vos tentatives ont chou, vous pouvez probablement remplacer votre shell
douverture de session existant par bash en utilisant exec, mais les mes sensibles doivent
sabstenir. Consultez la section A7) How can I make bash my login shell? dans la
FAQ de bash (http://tiswww.case.edu/php/chet/bash/FAQ).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

18

Chapitre 1 Dbuter avec bash

Voir aussi

man chsh ;

man passwd ;

man chpass ;

/etc/shells ;

la section A7) How can I make bash my login shell? dans la FAQ de bash
lURL http://tiswww.case.edu/php/chet/bash/FAQ ;

la recette 14.13, Fixer les autorisations, page 310 ;

la recette 14.19, Utiliser sudo de manire plus sre, page 318.

1.10. Obtenir bash pour Linux


Problme
Vous souhaitez obtenir bash pour votre systme Linux ou vous voulez tre certain
davoir la dernire version.

Solution
bash est fourni avec pratiquement toutes les distributions rcentes de Linux. Pour tre
certain de disposer de la dernire version compatible avec votre distribution, utilisez les
outils de gestion de paquets quelle offre. Pour mettre niveau ou installer des applications, vous devez tre root ou disposer de son mot de passe.
Pour certaines distributions Linux, la version de bash par dfaut est la version 2.x, avec
la version 3.x disponible sous bash3. Prenez soin de vrifier ce point. Le tableau 1-1 rcapitule les versions par dfaut dbut 2007. Les distributions mettent niveau leurs dpts assez souvent et les versions peuvent avoir chang. Par exemple, la dernire version
de Debian est passe bash version 3.1.
Tableau 1-1. Versions par dfaut des distributions Linux
Distribution

2.x dans
linstallation
initiale

Debian Sargea

2.05b

3.1dfsg-8 (testing & unstable)

3.0-12(1)-release

3.00.16(1)release

Debian Etcha

Sans objet (SO)

SO

3.1.17(1)-release

SO

Fedora Core 1

bash-2.05b31.i386.rpm

bash-2.05b34.i386.rpm

SO

SO

Fedora Core 2

bash-2.05b38.i386.rpm

SO

SO

SO

Fedora Core 3

SO

SO

bash-3.017.i386.rpm

bash-3.018.i386.rpm

[05/03/08]

bash Le livre de recettes

2.x dans les


mises jour

3.x dans
linstallation
initiale

3.x dans les


mises jour

Elodie FRITSCH <elodie.fritsch@total.com>

1.10. Obtenir bash pour Linux

19

Tableau 1-1. Versions par dfaut des distributions Linux (suite)


Distribution

2.x dans
linstallation
initiale

2.x dans les


mises jour

3.x dans
linstallation
initiale

Fedora Core 4

SO

SO

bash-3.031.i386.rpm

SO

Fedora Core 5

SO

SO

bash-3.16.2.i386.rpm

bash-3.19.fc5.1.i386.rpm

Fedora Core 6

SO

SO

bash-3.116.1.i386.rpm

SO

Knoppix 3.9 &


4.0.2

SO

SO

3.0-15

SO

Mandrake 9.2b

bash-2.05b14mdk.i586.rpm

SO

SO

SO

Mandrake 10.1c

bash-2.05b22mdk.i586.rpm

SO

SO

SO

Mandrake 10.2d

SO

SO

bash-3.02mdk.i586.rpm

SO

Mandriva
2006.0e

SO

SO

bash-3.06mdk.i586.rpm

SO

Mandriva
2007.0f

SO

SO

bash-3.17mdv2007.0.i586
.rpm

SO

OpenSUSE 10.0

SO

SO

3.00.16(1)release

3.0.17(1)-release

OpenSUSE 10.1

SO

SO

3.1.16(1)-release

SO

OpenSUSE 10.2

SO

SO

bash-3.155.i586.rpm

SO

3.x dans les


mises jour

SLED 10 RC3

SO

SO

3.1.17(1)-release

SO

RHEL 3.6,
CentOS 3.6

bash-2.05b.0(1)

SO

SO

SO

RHEL 4.4,
CentOS 4.4

SO

SO

3.00.15(1)release

SO

MEPIS 3.3.1

SO

SO

3.0-14

SO

Ubuntu 5.10g

SO

SO

3.0.16(1)

SO

Ubuntu 6.06g

SO

SO

3.1.17(1)-release

SO

Ubuntu 6.10gh

SO

SO

3.1.17(1)-release

SO

a. Debian Etch : voir aussi les paquets bash-builtins, bash-doc, bash-minimal et bash-static.
b. Mandrake 9.2 : voir aussi bash-completion-20030821-3mdk.noarch.rpm, bash-doc-2.05b-14mdk.
i586.rpm, bash1-1.14.7-31mdk.i586.rpm.
c. Mandrake 10.1 : voir aussi bash-completion-20040711-1mdk.noarch.rpm, bash-doc-2.05b22mdk.i586.rpm, bash1-1.14.7-31mdk.i586.rpm.
d. Mandrake 10.2 : voir aussi bash-completion-20050121-2mdk.noarch.rpm, bash-doc-3.0-2mdk.
i586.rpm.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

20

Chapitre 1 Dbuter avec bash


e.

Mandriva 2006.0 : voir aussi bash-completion-20050721-1mdk.noarch.rpm, bash-doc-3.0-6mdk.


i586.rpm.
f. Mandriva 2007.0 : voir aussi bash-completion-20060301-5mdv2007.0.noarch.rpm, bash-doc-3.
1-7mdv2007.0.i586.rpm.
g. Ubuntu : voir aussi les paquets bash-builtins, bash-doc, bash-static et abs-guide.
h. Ubuntu 6.10 cre le lien symbolique dash vers /bin/sh au lieu de bash comme dans les versions prcdentes et la plupart des autres distributions Linux (https://wiki.ubuntu.com/
DashAsBinSh).

Pour Debian Sarge et les systmes drivs de Debian, comme Knoppix, Ubuntu et
MEPIS, vrifiez que le fichier /etc/apt/sources.list dsigne un miroir Debian jour. Ensuite, utilisez les outils graphiques Synaptic, kpackage, gnome-apt ou Ajout/Suppression de
programmes, loutil aptitude en mode terminal ou la ligne de commande :
apt-get update && apt-get install bash bash3 bash-builtins bash-doc bash3doc

Pour les distributions Red Hat, y compris Fedora Core (FC) et Red Hat Enterprise Linux
(RHEL), utilisez loutil graphique Ajout/Suppression dapplications (si cet outil nest pas
accessible depuis le menu, saisissez redhat-config-packages & sur la ligne de commande
de RHEL3 ou, pour RHEL4, system-config-packages &). Pour un outil en ligne de commande uniquement, entrez :
up2date install bash

Pour Fedora Core et CentOS, vous pouvez suivre les directives donnes pour RHEL ou
la ligne de commande :
yum update bash

Pour SUSE, lancez la version graphique ou en mode terminal de YaST. Vous pouvez galement employer loutil RPM en ligne de commande.
Pour Mandriva/Mandrake, utilisez loutil graphique Rpmdrake ou la ligne de commande :
urpmi bash

Discussion
Puisquelles voluent trs rapidement, il nous est impossible de dcrire toutes les distributions Linux, mme les principales. Heureusement, cette volution concerne essentiellement la facilit dutilisation. vous ne devriez donc pas rencontrer trop de
difficults installer un logiciel sur votre distribution.
Si vous utilisez Knoppix, Ubuntu ou un autre Live CD, les mises jour et les installations choueront gnralement car le support est en lecture seule. Une fois installes sur
le disque dur, les versions de ces distributions peuvent tre mises niveau.
La commande apt-get update && apt-get install bash bash3 bash-builtins bashdoc bash3-doc prcdente gnrera des erreurs sur les systmes qui noffrent pas de paquet bash3. Vous pouvez les ignorer sans problme.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.11. Obtenir bash pour xBSD

21

Voir aussi

http://wiki.linuxquestions.org/wiki/Installing_Software ;

CentOS : http://www.centos.org/docs/4/html/rhel-sag-en-4/pt-pkg-management.html ;

Debian : http://www.debian.org/doc/, voir les manuels apt-HOWTO et Documentation dselect pour dbutants ;

http://www.debianuniverse.com/readonline/chapter/06 ;

Fedora Core : http://fedora.redhat.com/docs/yum/ ;

Red Hat Enterprise Linux : https://www.redhat.com/docs/manuals/enterprise/RHEL-3Manual/sysadmin-guide/pt-pkg-management.html ;

https://www.redhat.com/docs/manuals/enterprise/RHEL-4-Manual/sysadmin-guide/pt-pkgmanagement.html ;

Mandriva : http://www.mandriva.com/fr/community/users/documentation ;

http://doc.mandrivalinux.com/MandrakeLinux/101/fr/Starter.html/software-management.
html ;

http://doc.mandrivalinux.com/MandrakeLinux/101/fr/Starter.html/ch19s05.html ;

MEPIS : manuel du systme http://www.mepis-france.org/doc/ManuelMepisFr.pdf ;

OpenSuSE : http://fr.opensuse.org/Documentation ;

http://www.opensuse.org/User_Documentation ;

http://forge.novell.com/modules/xfmod/project/?yast ;

Ubuntu : http://www.ubuntulinux.org/support/documentation/helpcenter_view et http://


ubuntu.fr/aide/ (non officiel) ;

la recette 1.9, Faire de bash le shell par dfaut, page 16.

1.11. Obtenir bash pour xBSD


Problme
Vous souhaitez obtenir bash pour votre systme FreeBSD, NetBSD ou OpenBSD ou
vous voulez tre certain davoir la dernire version.

Solution
Pour savoir si bash est install, consultez le fichier /etc/shells. Pour installer ou mettre
jour bash, utilisez la commande pkg_add. Si vous matrisez parfaitement votre systme
BSD, servez-vous des outils de gestion des portages logiciels, mais nous nexaminerons
pas cette solution ici.
FreeBSD :
pkg_add -vr bash

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

22

Chapitre 1 Dbuter avec bash

Pour NetBSD, visitez la page Logiciels pour NetBSD (http://www.netbsd.org/fr/Documentation/software/) et recherchez le dernier paquet bash correspondant votre version
et architecture, puis excutez une commande similaire la suivante :
pkg_add -vu ftp://ftp.netbsd.org/pub/NetBSD/packages/pkgsrc-2005Q3/NetBSD2.0/i386/All/bash-3.0pl16nb3.tgz

Pour OpenBSD, servez-vous de la commande pkg_add -vr. Vous pouvez galement


adapter le chemin FTP votre version et architecture. Dautre part, une version compile statiquement est probablement disponible, par exemple ftp://ftp.openbsd.org/pub/
OpenBSD/3.8/packages/i386/bash-3.0.16p1-static.tgz.
pkg_add -vr ftp://ftp.openbsd.org/pub/OpenBSD/3.8/packages/i386/bash3.0.16p1.tgz

Discussion
FreeBSD et OpenBSD placent bash dans /usr/local/bin/bash, tandis que NetBSD utilise
/usr/pkg/bin/bash.
PC-BSD 1.2, un systme dexploitation Unix bas sur FreeBSD solide comme un roc ,
fournit bash 3.1.17(0) dans /usr/local/bin/bash, bien que le shell par dfaut reste csh.

Voir aussi

la recette 1.9, Faire de bash le shell par dfaut, page 16 ;

la recette 15.4, Tester des scripts sous VMware, page 339.

1.12. Obtenir bash pour Mac OS X


Problme
Vous souhaitez obtenir bash pour votre Mac ou vous voulez tre certain davoir la dernire version.

Solution
Selon la page de Chet Ramey ddie bash (http://tiswww.tis.case.edu/~chet/bash/bashtop.
html), Mac OS 10.2 (Jaguar) et les versions ultrieures sont livres avec bash sous le nom
/bin/sh. 10.4 (Tiger) propose la version 2.05b.0(1)-release (powerpc-apple-darwin8.0). Des
paquets OS X prcompils de bash-2.05 sont galement disponibles sur plusieurs sites
web, par exemple HMUG. La version de bash pour Darwin (sur lequel repose Mac OS
X) est disponible sur Fink ou DarwinPorts.

Discussion
Vous pouvez galement compiler une version plus rcente de bash partir des sources,
mais ce processus est dconseill aux dbutants.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.13. Obtenir bash pour Unix

23

Voir aussi

http://tiswww.tis.case.edu/~chet/bash/bashtop.html ;

http://www.hmug.org/pub/MacOS_X/BSD/Applications/Shells/bash/ ;

http://fink.sourceforge.net/pdb/package.php/bash ;

http://darwinports.opendarwin.org/ports.php?by=name&substr=bash.

1.13. Obtenir bash pour Unix


Problme
Vous souhaitez obtenir bash pour votre systme Unix ou vous voulez tre certain davoir
la dernire version.

Solution
Sil nest pas dj install ou sil ne se trouve pas parmi les programmes de votre systme
dexploitation, visitez la page de Chet Ramey ddie bash et consultez la section des
tlchargements des versions binaires. Vous pouvez galement le compiler partir des
fichiers sources (voir lannexe E, Compiler bash).

Discussion
Voici ce que prcise la page de Chet Ramey ddie bash (http://tiswww.tis.case.edu/~chet/
bash/bashtop.html) :
Les utilisateurs de Solaris 2.x, de Solaris 7 et de Solaris 8 peuvent obtenir une version
compile de bash-3.0 sur le site Sunfreeware. Sun fournit bash-2.03 avec les distributions Solaris 8, bash-2.05 en tant que programme reconnu par Solaris 9 et bash-3.0 en
tant que programme pris en charge avec Solaris 10 (directement sur le CD de Solaris
10).
Les utilisateurs dAIX peuvent obtenir les versions compiles des anciennes versions
de bash auprs du Groupe Bull, ainsi que les fichiers sources et binaires des versions
actuelles pour diffrentes variantes dAIX auprs de lUCLA. IBM propose bash-3.0
pour AIX 5L dans la bote outils AIX pour les applications [GNU/]Linux. Le format
utilis est RPM, que vous pouvez galement trouver au mme endroit.
Les utilisateurs de SGI peuvent obtenir une version stable de bash-2.05b partir de la
page SGI Freeware.
Les utilisateurs de HP-UX peuvent obtenir les versions compiles et sources de bash3.0 partir du site The Porting and Archive Centre for HP-UX.
Les utilisateurs de Tru64 Unix peuvent obtenir les versions compiles et sources de
bash-2.05b partir du site HP/Compaq Tru64 Unix Open Source Software Collection.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

24

Chapitre 1 Dbuter avec bash

Voir aussi

http://tiswww.tis.case.edu/~chet/bash/bashtop.html ;

http://www.sun.com/software/solaris/freeware/ ;

http://aixpdslib.seas.ucla.edu/packages/bash.html ;

http://www.ibm.com/servers/aix/products/aixos/linux/index.html ;

http://freeware.sgi.com/index-by-alpha.html ;

http://hpux.cs.utah.edu/ ;

http://hpux.connect.org.uk/hppd/hpux/Shells/ ;

http://hpux.connect.org.uk/hppd/hpux/Shells/bash-3.00.16/ ;

http://h30097.www3.hp.com/demos/ossc/html/bash.htm ;

la recette 1.9, Faire de bash le shell par dfaut, page 16 ;

lannexe E, Compiler bash, page 597.

1.14. Obtenir bash pour Windows


Problme
Vous souhaitez obtenir bash pour votre systme Windows ou vous voulez tre certain
davoir la dernire version.

Solution
Utilisez Cygwin.
Tlchargez http://www.cygwin.com/setup.exe et excutez-le. Rpondez aux questions et
choisissez les paquetages installer, en particulier bash, qui se trouve dans la catgorie
Shells (il est slectionn par dfaut). Au moment de lcriture de ces lignes, bash-3.2.1715 est disponible.
Une fois Cygwin install, vous devrez le configurer. Pour cela, consultez le guide de lutilisateur http://cygwin.com/cygwin-ug-net/.

Discussion
Extrait du site web de Cygwin :
Ce quest Cygwin
Cygwin est un environnement de type Linux pour Windows. Il est constitu de deux
parties :

Une DLL (cygwin1.dll), qui joue le rle de couche dmulation des API de Linux
et qui en fournit les fonctionnalits principales.

Un ensemble doutils, qui apportent lapparence de Linux.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.15. Obtenir bash sans linstaller

25

La DLL Cygwin fonctionne avec toutes les versions finales 32 bits x86 de Windows
(non les versions bta ou release candidate ), depuis Windows 95 lexception de
Windows CE.
Ce que nest pas Cygwin

Cygwin ne peut excuter des applications Linux natives sous Windows. Vous
devez recompiler lapplication partir des fichiers sources pour la faire fonctionner sous Windows.

Cygwin ne peut offrir aux applications Windows natives les caractristiques


dUnix (par exemple les signaux ou les ptys). Une fois encore, vous devez compiler vos applications partir des fichiers sources si vous voulez exploiter les possibilits de Cygwin.

Cygwin est un vritable environnement de type Unix sexcutant au-dessus de Windows. Cest un outil merveilleux, mais il peut tre parfois disproportionn. Le site http://
unxutils.sourceforge.net/ propose les versions Windows natives de certains utilitaires
GNU (sans bash).
Les Windows Services pour UNIX (http://www.microsoft.com/windowsserversystem/sfu/
default.mspx) pourraient galement vous intresser, mais leur dveloppement nest plus
vraiment assur et leur prise en charge va au moins jusquen 2011 (http://www.eweek.
com/article2/0,1895,1855274,00.asp).
http://jpsoft.com/ offre des shells en ligne de commande et graphiques, dont linterface est
plus cohrente avec DOS/Windows. Aucun des auteurs nest associ cette entreprise,
mais lun deux est un utilisateur satisfait de ces produits.

Voir aussi

http://www.cygwin.com/ ;

http://unxutils.sourceforge.net/ ;

http://www.microsoft.com/windowsserversystem/sfu/default.mspx ;

http://jpsoft.com/ ;

http://www.eweek.com/article2/0,1895,1855274,00.asp.

1.15. Obtenir bash sans linstaller


Problme
Vous souhaitez tester un shell ou un script shell sur un certain systme sans avoir le
temps ou les ressources de linstaller ou de lacheter.

Solution
Demandez un compte shell gratuit (ou presque) chez HP, Polar Home ou dautres fournisseurs.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

26

Chapitre 1 Dbuter avec bash

Discussion
Le programme Test drive de HP propose des comptes shell gratuit pour plusieurs
systmes dexploitation sur diffrents matriels HP. Pour plus dinformations, consultez
le site http://www.testdrive.hp.com/.
Polar Home offre de nombreux services gratuits et des comptes shell presque gratuits.
Voici un extrait de leur site web :
polarhome.com est un organisme ducatif non commercial dont lobjectif est de promouvoir les systmes dexploitation avec shell et les services Internet, en offrant des
comptes shell, des services de messagerie, ainsi que dautres services en ligne, sur tous
les systmes disponibles (actuellement Linux, OpenVMS, Solaris, AIX, QNX, IRIX,
HP-UX, Tru64, FreeBSD, OpenBSD, NetBSD et OPENSTEP).
[...]
Note : ce site est en dveloppement permanent et sappuie sur des connexions lentes
ou des petits serveurs qui ne sont plus utiliss. Par consquent, en tant quutilisateur/visiteur dun site non commercial, vous ne devez pas avoir de trop grandes attentes. Mme si polarhome.com fait le maximum pour offrir des services de niveau
professionnel, les utilisateurs ne doivent pas esprer plus quil nest possible.
polarhome.com est un site rparti, mais 90 % de ses ressources se trouvent Stockholm, en Sude.

Voir aussi

la liste de comptes shell gratuits : http://www.ductape.net/~mitja/freeunix.shtml ;

http://www.testdrive.hp.com/os/ ;

http://www.testdrive.hp.com/faq/ ;

http://www.polarhome.com/.

1.16. Documentation de bash


Problme
Vous souhaitez en apprendre plus sur bash, mais vous ne savez pas par o commencer.

Solution
Vous tes en train de lire ce livre, ce qui est dj un bon point de dpart ! Les autres
ouvrages des ditions OReilly qui traitent de bash et de lcriture de scripts sont : Le shell
bash de Cameron Newham et Introduction aux scripts shell de Nelson H.F. Beebe et Arnold Robbins.
Malheureusement, la documentation officielle de bash na jamais vraiment t disponible en ligne, jusqu aujourdhui. Vous deviez prcdemment tlcharger plusieurs archives, trouver tous les fichiers qui contenaient des informations, puis dchiffrer les
noms des fichiers afin dobtenir ce que vous souhaitiez. Nous avons fait tout ce travail

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

1.16. Documentation de bash

27

votre place et lavons plac sur notre site web consacr ce livre (http://www.bashcookbook.com/). Vous y trouverez lensemble de la documentation de rfrence officielle de
bash. Nhsitez pas le visiter et le faire connatre.

Documentation officielle
Le fichier contenant la FAQ officielle de bash se trouve ftp://ftp.cwru.edu/pub/bash/FAQ.
Consultez notamment la section qui concerne la documentation de bash, H2) What
kind of bash documentation is there? . Le guide de rfrence officiel est galement fortement conseill (voir ci-aprs).
La page web de Chet Ramey (le responsable actuel de bash) ddie bash (appele bashtop) contient une quantit impressionnante dinformations trs utiles (http://tiswww.
tis.case.edu/~chet/bash/bashtop.html). Chet assure galement la mise jour des documents suivants :
README
Fichier dcrivant bash : http://tiswww.tis.case.edu/chet/bash/README.
NEWS
Fichier donnant la liste des changements importants entre la version actuelle et la
version prcdente : http://tiswww.tis.case.edu/chet/bash/NEWS.
CHANGES
Historique complet des modifications apportes bash : http://tiswww.tis.case.edu/
chet/bash/CHANGES.
INSTALL
Instructions dinstallation : http://tiswww.tis.case.edu/chet/bash/INSTALL.
NOTES
Notes de configuration et de fonctionnement propres aux diffrentes platesformes : http://tiswww.tis.case.edu/chet/bash/NOTES.
COMPAT
Problmes de compatibilit entre bash3 et bash1 : http://tiswww.tis.case.edu/~chet/
bash/COMPAT.
Les dernires versions du code source et de la documentation de bash sont toujours disponibles ladresse http://ftp.gnu.org/gnu/bash/.
Nous vous conseillons fortement de tlcharger les sources et la documentation, mme
si vous utilisez des versions binaires prcompiles. Voici une courte liste de la documentation. Lannexe B fournit un index des exemples inclus et du code source. Consultez le
rpertoire ./doc disponible dans larchive des sources, par exemple http://ftp.gnu.org/gnu/
bash/bash-3.1.tar.gz, bash-3.1/doc :
.FAQ
Liste des questions les plus frquentes concernant bash, avec les rponses.
.INTRO
Courte introduction bash.
article.ms
Article sur bash que Chet a crit pour The Linux Journal.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

28

Chapitre 1 Dbuter avec bash

bash.1
Page de manuel de bash.
bashbug.1
Page de manuel de bashbug.
builtins.1
Page de manuel qui documente les commandes internes sorties de bash.1.
bashref.texi
Manuel de rfrence de bash.
bashref.info
Manuel de rfrence de bash, une fois trait par makeinfo.
rbash.1
Page de manuel du shell bash restreint.
readline.3
Page de manuel de readline.
Les fichiers .ps sont des versions PostScript des documents prcdents. Les fichiers .html
sont des versions HTML de la page de manuel et du manuel de rfrence. Les fichiers .0
sont des pages de manuel mises en forme. Les fichiers .txt sont des versions ASCII, obtenues avec groff -Tascii.
Voici ce que vous trouverez dans larchive de la documentation, par exemple http://ftp.
gnu.org/gnu/bash/bash-doc-3.1.tar.gz, bash-doc-3.1 :
.bash.0
Page de manuel de bash mise en forme (galement disponible aux formats PDF, ps
et HTML).
bashbug.0
Page de manuel de bashbug mise en forme.
bashref
The Bash Reference Guide (galement disponible aux formats PDF, ps, HTML et dvi).
builtins.0
Page de manuel de built-ins mise en forme.
.rbash.0
Page de manuel du shell bash restreint mise en forme.

Autre documentation

Bash pour le dbutant ladresse http://www.traduc.org/docs/guides/vf/Bash-BeginnersGuide/.

Guide avanc dcriture des scripts Bash ladresse http://abs.traduc.org/.

Writing Shell
scripts.php.

BASH Programming Introduction HOW-TO ladresse http://www.tldp.org/HOWTO/


Bash-Prog-Intro-HOWTO.html.

[05/03/08]

bash Le livre de recettes

Scripts

ladresse

http://www.linuxcommand.org/writing_shell_

Elodie FRITSCH <elodie.fritsch@total.com>

1.16. Documentation de bash

29

The Bash Prompt HOWTO ladresse http://www.tldp.org/HOWTO/Bash-PromptHOWTO/index.html.

Plutt ancien, mais encore trs utile : UNIX shell differences and how to change your
shell at http://www.faqs.org/faqs/unix-faq/shell/shell-differences/.

[Apples] Shell Scripting Primer ladresse http://developer.apple.com/documentation/


OpenSource/Conceptual/ShellScripting/.

Voir aussi

lannexe B, Exemples fournis avec bash, page 559.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2
Sortie standard

Sil ne produit aucune sortie, un logiciel est totalement inutile. Mais les entres/sorties
ont souvent t un point dlicat de linformatique. Si vous faites partie des vieux briscards, vous vous souvenez sans doute de lpoque o lexcution dun programme impliquait un important travail de configuration de ses entres/sorties. Certains
problmes ont disparu. Par exemple, il est dsormais inutile de demander des oprateurs de placer des bandes dans un lecteur, tout au moins sur les systmes bureautiques
que nous avons pu rencontrer. Cependant, quelques problmes perdurent.
Lun deux concerne la diversit des sorties possibles. Laffichage de donnes sur lcran
est diffrent de leur enregistrement dans un fichier, enfin cela semble diffrent. De mme, crire lenregistrement de donnes dans un fichier semble diffrent de leur criture
sur une bande, sur une mmoire flash ou sur dautres types de dispositifs. Et si vous souhaitez que la sortie dun programme aille directement dans un autre programme ? Les
dveloppeurs doivent-ils crire du code pour grer toutes sortes de priphrique de sortie, mme ceux qui nont pas encore t invents ? Les utilisateurs doivent-ils savoir
comment connecter les programmes quils emploient diffrentes sortes de
priphriques ? Sans trop y rflchir, cela ne semble pas vraiment la bonne solution.
Lune des ides sous-jacentes Unix est de tout considrer comme un fichier (une suite
ordonne doctets). Le systme dexploitation est responsable de cette mise en uvre.
Peu importe que vous criviez dans un fichier sur un disque, sur le terminal, sur un lecteur de bande, sur une cl mmoire, etc. Votre programme doit juste savoir comment
crire dans un fichier et le systme dexploitation soccupe du reste. Cette approche simplifie normment le problme. La question suivante est donc quest-ce quun
fichier ? . Comment un programme sait-il crire dans un fichier qui reprsente la fentre dun terminal, un fichier sur le disque ou toute autre sorte de fichiers ? Cest trs
simple, il suffit de sen remettre au shell.
Lorsque vous excutez un programme, vous devez encore associer ses fichiers de sortie
et dentre (nous verrons comment au chapitre suivant). Cet aspect na pas disparu, mais
le shell la rendu trs facile. Voici une commande excessivement simple :
$ faireQuelqueChose < fichierEntree > fichierSortie

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

32

Chapitre 2 Sortie standard

Elle lit les donnes en entre depuis fichierEntree et envoie sa sortie vers fichierSortie. Si vous omettez > fichierSortie, la sortie saffiche sur la fentre du terminal. Si
vous omettez < fichierEntree, le programme lit son entre depuis le clavier. Le programme ne sait absolument pas o va sa sortie, ni do provient son entre. Vous pouvez rediriger la sortie comme bon vous semble (y compris vers un autre programme)
grce aux possibilits offertes par bash.
Mais ce nest que le dbut. Dans ce chapitre, nous prsentons diffrentes manires de
gnrer une sortie et les mthodes du shell pour lenvoyer vers diffrents destinations.

2.1. crire la sortie sur le terminal ou une


fentre
Problme
Vous souhaitez une sortie simple partir de vos commandes du shell.

Solution
Utilisez la commande interne echo. Tous les paramtres placs sur la ligne de commande
sont affichs lcran. Par exemple :
echo Veuillez patienter.

affiche
Veuillez patienter.

Vous pouvez tester cette simple session en entrant la commande linvite de bash (le
caractre $) :
$ echo Veuillez patienter.
Veuillez patienter.
$

Discussion
echo est lune des commandes bash les plus simples. Elle affiche lcran les arguments
donns sur la ligne de commande. Cependant, quelques remarques sont ncessaires.
Tout dabord, le shell analyse les arguments de la ligne de commande decho, comme
pour nimporte quelle autre ligne de commande. Autrement dit, il applique toutes les
substitutions, correspondances de caractres gnriques et autres interprtations avant
de passer les arguments echo. Ensuite, puisque les arguments sont analyss, les espaces
qui les sparent sont ignores :
$ echo ces
mots
sont
ces mots sont vraiment spars
$

vraiment

spars

En gnral, lindulgence du shell vis--vis des espaces qui sparent les arguments est plutt la bienvenue. Dans ce cas, avec echo, elle savre assez dconcertante.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.2. crire la sortie en conservant les espaces

33

Voir aussi

help echo ;

help printf ;

la recette 2.3, Mettre en forme la sortie, page 34 ;

la recette 15.6, crire une commande echo portable, page 342 ;

la recette 19.1, Oublier les autorisations dexcution, page 485 ;

la section Options et squences dchappement de echo, page 539 ;

la section printf, page 540.

2.2. crire la sortie en conservant les espaces


Problme
Vous souhaitez que la sortie conserve les espaces saisies.

Solution
Placez la chane entre des apostrophes ou des guillemets. Ainsi, pour lexemple prcdent, les espaces sont affiches :
$ echo "ces
ces
mots
$

mots
sont

sont
vraiment
spars"
vraiment
spars

mots
sont

sont
vraiment
spars'
vraiment
spars

Ou encore :
$ echo 'ces
ces
mots
$

Discussion
Puisque les mots sont placs entre des apostrophes ou des guillemets, ils reprsentent
un seul argument pour la commande echo. Cet argument est une chane et le shell ninterfre pas forcment avec son contenu. Si vous utilisez des apostrophes (''), le shell
nexamine pas le contenu de la chane. Si vous la placez entre des guillemets ("), certaines substitutions ont lieu (variable, expansion du tilde et substitution de commandes),
mais, dans cet exemple, le shell na rien modifier. En cas de doute, utilisez des apostrophes.

Voir aussi

help echo ;

help printf ;

le chapitre 5, Variables du shell, page 85, pour plus dinformations sur la substitution ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

34

Chapitre 2 Sortie standard

la recette 2.3, Mettre en forme la sortie, page 34 ;

la recette 15.6, crire une commande echo portable, page 342 ;

la recette 19.1, Oublier les autorisations dexcution, page 485 ;

la section Options et squences dchappement de echo, page 539.

2.3. Mettre en forme la sortie


Problme
Vous souhaitez avoir une meilleure matrise de la mise en forme et du placement de la
sortie.

Solution
Utilisez la commande interne printf. Par exemple :
$ printf '%s = %d\n' Lignes $LINES
Lignes = 24
$

ou :
$ printf '%-10.10s = %4.2f\n' 'GigaHertz' 1.92735
GigaHertz
= 1.93
$

Discussion
La commande interne printf fonctionne comme son quivalent de la bibliothque C. Le
premier argument est une chane de format. Les arguments suivants sont mis en forme
conformment aux indications de format (%).
Les nombres placs entre le symbole % et le type de format (s ou f dans notre exemple)
apportent des dtails de mise en forme supplmentaires. Pour le format en virgule f lottante (f), la premire valeur (4 dans le modificateur 4.2) fixe la largeur du champ entier. La deuxime (2) indique le nombre de chiffres placs aprs la virgule. Notez que la
rponse est arrondie.
Dans le cas dune chane, la premire valeur prcise la taille maximum du champ, tandis
que la seconde indique sa taille minimum. La chane sera tronque ou comble par des
espaces, selon les besoins. Lorsque les modificateurs de taille maximum et minimum
sont gaux, la longueur de la chane est exactement celle indique. Le symbole - ajout
au modificateur signifie que la chane doit tre aligne gauche ( lintrieur de la largeur du champ). Sans ce symbole, la chane est aligne droite :
$ printf '%10.10s = %4.2f\n' 'GigaHertz' 1.92735
GigaHertz = 1.93
$

La chane en argument peut tre place ou non entre guillemets. Utilisez-les si vous souhaitez conserver lespacement indiqu ou si vous devez annuler la signification particu-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.4. crire la sortie sans le saut de ligne

35

lire de certains caractres de la chane (ce nest pas le cas dans notre exemple). Il est
prfrable de prendre lhabitude de placer entre guillemets les chanes passes printf,
car il est trs facile de les oublier.

Voir aussi

help printf ;

http://www.opengroup.org/onlinepubs/009695399/functions/printf.html ;

Le shell bash de Cameron Newham (ditions OReilly), page 171, ou toute documentation de rfrence sur la fonction printf du langage C ;

la recette 15.6, crire une commande echo portable, page 342 ;

la recette 19.11, Constater un comportement trange de printf, page 497 ;

la section printf, page 540.

2.4. crire la sortie sans le saut de ligne


Problme
Vous souhaitez que le saut de ligne par dfaut gnr par echo soit retir de la sortie.

Solution
Avec printf, il suffit denlever le caractre \n dans la chane de format. Pour echo, utilisez
loption -n.
$ printf "%s %s" invite suivante
invite suivante$

Ou :
$ echo -n invite
invite$

Discussion
Puisque la chane de format (le premier argument) de printf ninclut aucun caractre de
saut de ligne, le caractre dinvite ($) apparat immdiatement droite de la chane affiche. Cette caractristique est utile dans les scripts shell, lorsque laffichage de la sortie
est ralis sur plusieurs instructions, avant de terminer la ligne, ou bien lorsque vous
voulez afficher une invite lutilisateur avant de lire les donnes en entre.
Avec la commande echo, il existe deux manires dliminer le saut de ligne. Premirement, loption -n supprime le saut de ligne final. La commande echo dispose galement
de plusieurs squences dchappement ayant une signification particulire, similaires
celles des chanes du langage C (par exemple, \n pour le saut de ligne). Pour les utiliser,
vous devez invoquer echo avec loption -e. Lune des squences dchappement est \c.
Elle naffiche pas un caractre, mais empche la gnration du saut de ligne final. Voici
donc une deuxime solution :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

36

Chapitre 2 Sortie standard


$ echo -e 'salut\c'
salut$

La commande printf est puissante, offre une grande souplesse de mise en forme et implique peu de surcot. En effet, il sagit dune commande interne, contrairement
dautres shells ou danciennes versions de bash, dans lesquels printf est un programme
excutable distinct. Pour toutes ces raisons, nous lutiliserons dans plusieurs exemples
de ce livre.

Voir aussi

help echo ;

help printf ;

http://www.opengroup.org/onlinepubs/009695399/functions/printf.html ;

le chapitre 3, Entre standard, page 59, notamment la recette 3.5, Lire lentre de lutilisateur, page 64 ;

la recette 2.3, Mettre en forme la sortie, page 34 ;

la recette 15.6, crire une commande echo portable, page 342 ;

la recette 19.11, Constater un comportement trange de printf, page 497 ;

la section Options et squences dchappement de echo, page 539 ;

la section printf, page 540.

2.5. Enregistrer la sortie dune commande


Problme
Vous souhaitez conserver la sortie gnre par une commande en la plaant dans un fichier.

Solution
Utilisez le symbole > pour indiquer au shell de rediriger la sortie vers un fichier. Par
exemple :
$ echo il faut le remplir
il faut le remplir
$ echo il faut le remplir > fichier.txt
$

Vrifions le contenu de fichier.txt :


$ cat fichier.txt
il faut le remplir
$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.6. Enregistrer la sortie vers dautres fichiers

37

Discussion
La premire ligne de lexemple montre une commande echo dont les trois arguments
sont affichs. La deuxime ligne de code utilise > pour rediriger cette sortie vers le fichier nomm fichier.txt. Cest pourquoi, aucune sortie napparat aprs la commande
echo.
La seconde partie de lexemple invoque la commande cat pour afficher le contenu du
fichier. Vous pouvez constater quil contient la sortie de la commande echo.
La commande cat tire son nom du mot concatnation. Elle concatne la sortie des fichiers
indiqus sur la ligne de commande, comme dans cat fichier1 fichierdeux autrefichier encoresdesfichiers. Le contenu de ces fichiers est envoy, lun aprs lautre,
sur la fentre de terminal. Si un fichier volumineux a t coup en deux, il peut nouveau tre reconstitu (cest--dire concatn) en envoyant la sortie vers un troisime
fichier :
$ cat premiere.moitie deuxieme.moitie > fichier.entier

Notre commande cat fichier.txt nest donc quun cas trivial de concatnation dun
seul fichier, avec le rsultat affich lcran. Mme si cat offre dautres fonctionnalits,
elle est principalement utilise pour afficher le contenu dun fichier lcran.

Voir aussi

man cat ;

la recette 17.21, Numroter les lignes, page 467.

2.6. Enregistrer la sortie vers dautres fichiers


Problme
Vous souhaitez enregistrer la sortie vers dautres emplacements que le rpertoire courant.

Solution
Prcisez un nom de chemin lors de la redirection de la sortie. Par exemple :
$ echo des donnes supplmentaires > /tmp/echo.out

Ou :
$ echo des donnes supplmentaires > ../../par.ici

Discussion
Le nom de fichier plac derrire le caractre de redirection (>) est en ralit un nom de
chemin. Sil ne commence pas par des qualificateurs, le fichier est plac dans le rpertoire courant.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

38

Chapitre 2 Sortie standard

Si le nom de fichier commence par une barre oblique (/), le nom de chemin est alors
absolu et le fichier est plac dans la hirarchie du systme de fichiers indique (larborescence), qui commence la racine ( condition que tous les rpertoires intermdiaires
existent et que vous ayez lautorisation de les traverser). Nous avons utilis /tmp car ce
rpertoire est universellement disponible sur pratiquement tous les systmes Unix.
Dans cet exemple, le shell cre le fichier nomm echo.out dans le rpertoire /tmp.
Notre deuxime exemple place la sortie dans ../../par.ici en utilisant un chemin relatif.
La partie .. est un rpertoire au nom particulier qui existe dans chaque rpertoire et qui
fait rfrence au rpertoire parent. Ainsi, chaque occurrence de .. remonte dun niveau
dans larborescence du systme de fichiers (vers la racine, qui pourtant ne se trouve pas
habituellement au sommet dun arbre). Le point important ici est que nous pouvons
rediriger la sortie, si nous le souhaitons, vers un fichier plac dans un rpertoire totalement diffrent de celui dans lequel la commande est excute.

Voir aussi

Le shell bash de Cameron Newham (ditions OReilly), pages 710, pour une introduction aux fichiers, aux rpertoires et la notation pointe (cest--dire . et ..).

2.7. Enregistrer la sortie de la commande ls


Problme
Vous avez essay denregistrer la sortie dune commande ls laide dune redirection,
mais le format du fichier rsultant ne vous convient pas.

Solution
Utilisez loption -C de ls lorsque vous redirigez la sortie.
Voici une commande ls qui affiche le contenu dun rpertoire :
$ ls
a.out
$

cong.txt def.conf

fichier.txt autre.txt zebres.liste

Lorsque la sortie est redirige vers un fichier par >, le contenu de celui-ci est :
$ ls > /tmp/enreg.out
$ cat /tmp/enreg.out
a.out
cong.txt
def.conf
fichier.txt
autre.txt
zebres.liste
$

Utilisons prsent loption -C :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.8. Envoyer la sortie et les erreurs vers des fichiers diffrents


$ ls -C > /tmp/enreg.out
$ cat /tmp/enreg.out
a.out cong.txt def.conf
$

39

fichier.txt autre.txt zebres.liste

Nous pouvons galement choisir loption -1 de ls sans la redirection pour obtenir la


prsentation suivante :
$ ls -1
a.out
cong.txt
def.conf
fichier.txt
autre.txt
enreg.out
zebres.liste
$

La premire tentative de redirection permet alors dobtenir cette sortie.

Discussion
Alors que vous estimiez comprendre le fonctionnement de la redirection, vous lessayez
sur une simple commande ls et vous nobtenez pas ce que vous attendiez.
La redirection du shell est conue pour tre transparente tous les programmes. Ils ne
contiennent donc aucun code particulier pour que leur sortie soit redirigeable. Le shell
prend en charge la redirection de la sortie laide du symbole >. Cependant, un programme peut contenir du code qui dtermine si sa sortie a t redirige. Il peut alors se
comporter diffremment et cest le cas de ls.
Les programmeurs de ls ont estim quune sortie dirige vers lcran doit tre affiche
en colonne (option -C), puisque lespace disponible est limit. En revanche, si elle est
dirige vers un fichier, ils ont considr que vous prfreriez sans doute avoir un fichier
par ligne (option -1). En effet, vous pouvez alors utiliser celui-ci pour dautres oprations (un post-traitement), plus faciles mettre en uvre si chaque nom de fichier se
trouve sur sa propre ligne.

Voir aussi

man ls ;

la recette 2.6, Enregistrer la sortie vers dautres fichiers, page 37.

2.8. Envoyer la sortie et les erreurs vers des


fichiers diffrents
Problme
Vous attendez une sortie dun programme, mais vous ne voulez pas quelle soit pollue
par les messages derreur. Vous souhaitez enregistrer les messages derreur, mais il est
plus difficile de les retrouver lorsquils sont mlangs la sortie.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

40

Chapitre 2 Sortie standard

Solution
Redirigez la sortie et les messages derreur vers des fichiers diffrents :
$ programme 1> messages.out 2> message.err

Ou encore :
$ programme > messages.out 2> message.err

Discussion
Dans cet exemple, le shell cre deux fichiers de sortie distincts. Le premier, messages.out,
va recevoir la sortie gnre par programme. Si ce programme produit des messages derreur, ils sont redirigs vers message.err.
Dans les syntaxes 1> et 2>, le chiffre est un descripteur de fichier. 1 correspond STDOUT
et 2 STDERR. Lorsque le chiffre est absent, la sortie par dfaut est STDOUT.

Voir aussi

la recette 2.6, Enregistrer la sortie vers dautres fichiers, page 37 ;

la recette 2.13, Oublier la sortie, page 43.

2.9. Envoyer la sortie et les erreurs vers le


mme fichier
Problme
Grce une redirection, les messages derreur et de sortie peuvent tre enregistrs dans
des fichiers spars, mais comment les placer dans un mme fichier ?

Solution
Utilisez la syntaxe du shell pour rediriger les messages derreur standard vers la mme
destination que la sortie standard.
Voici la version recommande :
$ lesDeux >& fichierSortie

Ou encore :
$ lesDeux &> fichierSortie

La version suivante est plus ancienne et plus longue :


$ lesDeux > fichierSortie 2>&1
lesDeux est simplement notre programme (imaginaire) qui gnre une sortie vers

STDERR et vers STDOUT.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.10. Ajouter la sortie un fichier existant

41

Discussion
&> et >& sont simplement des raccourcis qui redirigent STDOUT et STDERR vers la
mme destination. Cest prcisment ce que nous souhaitons.
Dans le troisime exemple, 1 semble tre la cible de la redirection, mais >& indique que
1 doit tre considr comme un descripteur de fichier la place dun nom de fichier. En
ralit, 2>& constitue une seule entit, prcisant que la sortie standard (2) est redirige
(>) vers le descripteur de fichier (&) qui suit (1). 2>& doit tre utilis tel quel, sans espace,
ou 2 sera considr comme un autre argument et & aura une signification totalement
diffrente (excuter la commande en arrire-plan).
Pour vous aider, vous pouvez considrer que tous les oprateurs de redirection commencent par un chiffre (par exemple 2>), mais que le chiffre par dfaut de > est 1, cest-dire le descripteur de fichier de la sortie standard.
Vous pouvez galement effectuer la redirection dans lautre sens, mme si elle est moins
lisible, et rediriger la sortie standard vers la destination de lerreur standard :
$ lesDeux 2> fichierSortie 1>&2

1 dsigne la sortie standard et 2 lerreur standard. En suivant notre raisonnement prcdent, nous aurions pu crire la dernire redirection sous la forme >&2, puisque 1 est le
descripteur par dfaut de >. Cependant, nous estimons que la ligne est plus facile lire
lorsque les chiffres sont indiqus explicitement dans la redirection vers des fichiers.
Faites attention lordre du contenu dans le fichier de sortie. Les messages derreurs
peuvent parfois apparatre plus tt dans le fichier qu lcran. Ce comportement est li
au fait que lerreur standard nutilise pas de tampons. Leffet est plus prononc lorsque
lcriture se fait dans un fichier la place de lcran.

Voir aussi

la recette 2.6, Enregistrer la sortie vers dautres fichiers, page 37 ;

la recette 2.13, Oublier la sortie, page 43.

2.10. Ajouter la sortie un fichier existant


Problme
Chaque fois que vous redirigez la sortie, un nouveau fichier est cr. Comment pouvezvous la rediriger une deuxime (une troisime, etc.) fois sans craser le fichier prcdemment obtenu ?

Solution
Les doubles symboles suprieurs (>>) sont un redirecteur bash qui signifie ajouter la
sortie :
$ ls > /tmp/ls.out
$ cd ../ailleurs

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

42

Chapitre 2 Sortie standard


$ ls >> /tmp/ls.out
$ cd ../autrerep
$ ls >> /tmp.ls.out
$

Discussion
La premire ligne comporte une redirection qui supprime le fichier sil existait dj et
envoie la sortie de la commande ls vers un nouveau fichier vide.
Les deuxime et troisime invocations de ls emploient le double symbole suprieur
(>>) pour indiquer que la sortie doit tre ajoute au fichier et non le remplacer.

Voir aussi

la recette 2.6, Enregistrer la sortie vers dautres fichiers, page 37 ;

la recette 2.13, Oublier la sortie, page 43.

2.11. Utiliser seulement le dbut ou la fin dun


fichier
Problme
Vous souhaitez afficher ou utiliser uniquement le dbut ou la fin dun fichier.

Solution
Utilisez les commandes head ou tail. Par dfaut, head affiche les dix premires lignes
dun fichier, tandis que tail en affiche les dix dernires. Si plusieurs fichiers sont donns
en argument, les dix lignes correspondantes de chacun sont affiches. Loption -nombre
(par exemple -5) ajuste le nombre de lignes produites en sortie. tail dispose galement
des options -f et -F qui continuent afficher la fin du fichier au fur et mesure que des
lignes lui sont ajoutes. Son option + est galement trs intressante, comme nous le
verrons la recette 2.12, page 43.

Discussion
Avec cat, grep, sort, cut et uniq, head et tail font partie des outils Unix de manipulation
de texte les plus employs. Si vous ne les connaissez pas encore, vous vous rendrez rapidement compte quelles sont indispensables.

Voir aussi

la recette 2.12, Sauter len-tte dun fichier, page 43 ;

la recette 7.1, Rechercher une chane dans des fichiers, page 150 ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.12. Sauter len-tte dun fichier

43

la recette 8.1, Trier votre affichage, page 171 ;

la recette 8.4, Couper des parties de la sortie, page 176 ;

la recette 8.5, Retirer les lignes identiques, page 177 ;

la recette 17.21, Numroter les lignes, page 467.

2.12. Sauter len-tte dun fichier


Problme
Vous disposez dun fichier contenant une ou plusieurs lignes den-tte et souhaitez traiter uniquement les donnes, en sautant cet en-tte.

Solution
Utilisez la commande tail avec un argument particulier. Par exemple, voici comment
sauter la premire ligne dun fichier :
$ tail +2 lignes
Ligne 2
Ligne 4
Ligne 5

Discussion
En passant tail un argument constitu dun tiret (-) et dun nombre, vous indiquez le
nombre de ligne afficher partir de la fin du fichier. Ainsi, tail -10 fichier prsente
les dix dernires lignes de fichier, ce qui correspond au comportement par dfaut. En
revanche, si le nom est prcd dun signe plus (+), il correspond un dcalage par rapport au dbut du fichier. Par consquent, tail +1 fichier affiche lintgralit du fichier,
tout comme cat. +2 passe la premire ligne, etc.

Voir aussi

man tail ;

la recette 13.11, Configurer une base de donnes MySQL, page 271.

2.13. Oublier la sortie


Problme
Parfois, vous ne souhaitez pas enregistrer la sortie dans un fichier. En ralit, vous voulez mme quelquefois ne plus la voir.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

44

Chapitre 2 Sortie standard

Solution
Redirigez la sortie vers /dev/null :
$ find / -name fichier -print 2> /dev/null

Ou :
$ bavard >/dev/null 2>&1

Discussion
Vous pourriez rediriger la sortie vers un fichier, puis le supprimer. Il existe cependant
une solution plus simple. Les systmes Unix et Linux disposent dun priphrique spcial qui ne correspond pas du matriel rel, mais une benne bits dans laquelle vous
pouvez vider les donnes inutiles. Ce priphrique se nomme /dev/null. Toutes les donnes crites sur ce priphrique disparaissent simplement et noccupent donc aucune
place sur le disque. La redirection facilite son utilisation.
Dans le premier exemple, seules les informations envoyes sur lerreur standard sont jetes. Dans le deuxime, les donnes sur la sortie et lerreur standard disparaissent.
Parfois, mais ce cas est rare, vous pourriez vous trouver devant un systme de fichiers
/dev en lecture seule (par exemple, sur certains serveurs dinformation scuriss). Dans
cette situation, la solution consistant crire dans un fichier puis le supprimer nest
plus envisageable.

Voir aussi

la recette 2.6, Enregistrer la sortie vers dautres fichiers, page 37.

2.14. Enregistrer ou runir la sortie de


plusieurs commandes
Problme
Vous souhaitez capturer la sortie par une redirection, mais vous excutez plusieurs commandes sur une seule ligne.
$ pwd; ls; cd ../ailleurs; pwd; ls > /tmp/tout.out

La redirection place la fin de la ligne ne sapplique qu la dernire commande, cest-dire la dernire commande ls. Les sorties de toutes les autres commandes apparaissent lcran. Autrement dit, elles ne sont pas rediriges.

Solution
Utilisez les accolades { } pour regrouper les commandes. La redirection sapplique alors
la sortie de toutes les commandes du groupe. Par exemple :
$ { pwd; ls; cd ../ailleurs; pwd; ls; } > /tmp/tout.out

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.14. Enregistrer ou runir la sortie de plusieurs commandes

45

Cette solution recle quelques piges subtils. Les accolades sont en ralit des mots rservs et doivent donc tre entoures despaces. De
mme, le point-virgule plac aprs la dernire commande du groupe
est obligatoire (avant laccolade fermante).

Vous pourriez galement utiliser les parenthses ( ) pour demander bash dexcuter
les commandes dans un sous-shell, puis de rediriger lintgralit de la sortie produite
par ce sous-shell. Par exemple :
$ (pwd; ls; cd ../ailleurs; pwd; ls) > /tmp/tout.out

Discussion
Bien que ces deux solutions semblent similaires, elles prsentent deux diffrences importantes. La premire est dordre syntaxique, la seconde smantique. Syntaxiquement,
les accolades doivent tre entoures despaces et la dernire commande de la liste doit
se terminer par un point-virgule. Tout cela nest pas obligatoire avec les parenthses. Cependant, la diffrence la plus importante est dordre smantique, cest--dire la signification des constructions. Les accolades ne sont quun mcanisme permettant de
regrouper plusieurs commandes afin de ne pas tre oblig de rediriger sparment chacune delles. En revanche, les commandes places entre parenthses sexcutent dans
une autre instance du shell ; dans un sous-shell cr par le shell courant.
Le sous-shell est quasiment identique au shell courant. Les variables denvironnement,
y compris $PATH, sont les mmes, mais les signaux sont traits diffremment (nous reviendrons sur les signaux la recette 10.6, page 215). Il existe donc une grande diffrence
avec lapproche sous-shell. Dans ce cas, les commandes cd sont excutes dans le sousshell et, lorsque celui-ci se termine, le shell principal na pas chang dtat. Autrement
dit, le rpertoire de travail est le mme et ses variables ont toujours les mmes valeurs.
Si vous utilisez des accolades, le rpertoire de travail change (../ailleurs dans notre exemple). Toute autre modification apporte, par exemple aux variables, se font dans linstance en cours du shell. Mme si les deux approches donnent le mme rsultat, leurs
effets sont trs diffrents.
Avec les accolades, vous pouvez crer des blocs de branchement plus concis (voir la recette 6.2, page 116). Par exemple, vous pouvez rduire le code suivant :
if [ $resultat = 1 ]; then
echo "Le rsultat est 1 ; excellent."
exit 0
else
echo "Ouh l l, disparaissez ! "
exit 120
fi

en celui-ci :
[ $resultat = 1 ] \
&& { echo "Le rsultat est 1 ; excellent." ; exit 0;
|| { echo "Ouh l l, disparaissez ! " ; exit 120; }

[05/03/08]

bash Le livre de recettes

} \

Elodie FRITSCH <elodie.fritsch@total.com>

46

Chapitre 2 Sortie standard

Vous choisirez la solution qui correspond votre style ou celle que vous pensez la plus
lisible.

Voir aussi

la recette 6.2, Conditionner lexcution du code, page 116 ;

la recette 10.6, Intercepter les signaux, page 215 ;

la recette 15.1, Trouver bash de manire portable, page 334 ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490 ;

la recette 19.8, Oublier que les tubes crent des sous-shells, page 493 ;

la section Variables internes, page 510, pour en savoir plus sur BASH_SUBSHELL.

2.15. Relier une sortie une entre


Problme
Vous souhaitez que la sortie dun programme serve dentre un autre programme.

Solution
Vous pouvez rediriger la sortie du premier programme vers un fichier temporaire, puis
utilisez celui-ci comme entre du deuxime programme. Par exemple :
$ cat un.fichier unAutre.fichier > /tmp/cat.out
$ sort < /tmp/cat.out
...
$ rm /tmp/cat.out

Vous pouvez galement runir toutes ces tapes en une seule, en envoyant directement
la sortie vers le deuxime programme grce au symbole | (tube) :
$ cat un.fichier unAutre.fichier | sort

Rien ne vous interdit de lier plusieurs commandes en utilisant autant de tubes que
ncessaire :
$ cat mes* | tr 'a-z' 'A-Z' | uniq | awk -f transformation.awk | wc

Discussion
Grce aux tubes, vous navez pas inventer un nom de fichier temporaire, vous en souvenir, puis ne pas oublier de le supprimer.
Des programmes comme sort sont capables de lire sur lentre standard (par une redirection avec le symbole <), mais galement partir dun fichier. Par exemple :
$ sort /tmp/cat.out

au lieu de rediriger lentre vers sort :


$ sort < /tmp/cat.out

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.16. Enregistrer une sortie redirige vers une entre

47

Ce fonctionnement (utiliser le fichier indiqu ou lentre standard) est une caractristique classique des systmes Unix/Linux. Cest un modle suivre lorsque des commandes doivent tre relies les unes aux autres par le mcanisme de tube. Si vous crivez vos
programmes et vos scripts shell ainsi, ils vous seront plus utiles, ainsi quaux personnes
avec qui vous partagez votre travail.
Vous pouvez tre bahi par la puissante simplicit du mcanisme de tube et mme le
voir comme un mcanisme de traitement parallle rudimentaire. Deux commandes
(programmes) peuvent sexcuter en parallle et partager des donnes ; la sortie de
lune est lentre de lautre. Elles nont pas sexcuter squentiellement (la premire
devant tre termine avant que la seconde puisse dmarrer). La deuxime commande
reoit des donnes ds quelles sont fournies par la premire.
Cependant, vous devez savoir que les commandes excutes de cette manire (cest--dire, connectes par des tubes) utilisent des sous-shells spars. Mme si cette subtilit
peut souvent tre ignore, elle a parfois des implications trs importantes. Nous y reviendrons la recette 19.8, page 493.
Prenons lexemple dune commande comme svn -v log | less. Si less se termine avant
que Subversion ait fini denvoyer des donnes, vous obtenez une erreur comme svn:
Write error: Broken pipe . Mme si ce nest pas trs agrable, ce nest pas grave. Cela
se produit ds que vous envoyez de grandes quantits de donnes des programmes
comme less. En gnral, vous quittez less ds que vous avez trouv ce que vous recherchiez, mme si dautres donnes transitent encore par le tube.

Voir aussi

la recette 3.1, Lire les donnes dentre depuis un fichier, page 59 ;

la recette 19.8, Oublier que les tubes crent des sous-shells, page 493.

2.16. Enregistrer une sortie redirige vers une


entre
Problme
Vous souhaitez dboguer une longue suite dentres/sorties lies par des tubes, comme
la suivante :
$ cat mes* | tr 'a-z' 'A-Z' | uniq | awk -f transformation.awk | wc

Comment pouvez-vous savoir ce qui se passe entre uniq et awk, sans interrompre la suite
de tubes ?

Solution
La solution ce problme consiste utiliser ce que les plombiers appellent un raccord
en T. Pour bash, il sagit dutiliser la commande tee afin de dcomposer la sortie en deux
f lux identiques, lun dirig vers un fichier, lautre sur la sortie standard afin de ne pas
interrompre les tubes.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

48

Chapitre 2 Sortie standard

Dans cet exemple, nous analysons le fonctionnement dune longue suite de tubes en insrant la commande tee entre les commandes uniq et awk :
$ ... uniq | tee /tmp/x.x | awk -f transformation.awk ...

Discussion
La commande tee crit la sortie vers le fichier indiqu en paramtre, ainsi que vers la
sortie standard. Dans cet exemple, les donnes sont envoyes dans /tmp/x.x et vers awk,
cest--dire la commande laquelle la sortie de tee est connecte via le symbole |.
Ne vous proccupez pas du fonctionnement des diffrentes commandes de ces exemples. Nous voulons uniquement illustrer lemploi de tee dans diffrents cas.
Commenons par une ligne de commande plus simple. Supposez que vous vouliez enregistrer la sortie dune commande longue afin de la consulter plus tard, tout en suivant
le rsultat de son excution lcran. Une commande telle que :
find / -name '*.c' -print | less

risque de trouver un grand nombre de fichiers sources C et donc de remplir plus que la
fentre. En utilisant more ou less, vous pouvez examiner plus facilement la sortie, mais,
une fois la commande termine, vous ne pouvez pas revoir la sortie sans relancer la
commande. Bien entendu, vous pouvez excuter la commande et enregistrer le rsultat
dans un fichier :
find / -name '*.c' -print > /tmp/toutes.mes.sources

Cependant, vous devez attendre quelle soit termine avant de consulter le fichier. (Daccord, nous avons tail -f, mais ce nest pas le propos ici.) La commande tee peut remplacer une simple redirection de la sortie standard :
find / -name '*.c' -print | tee /tmp/toutes.mes.sources

Dans cet exemple, puisque la sortie de tee nest pas redirige, elle est affiche lcran.
En revanche, la copie de la sortie est envoye vers un fichier, qui pourra tre examin
par la suite (par exemple, cat /tmp/toutes.mes.sources).
Vous remarquerez galement que, dans ces exemples, nous navons pas redirig lerreur
standard. Cela signifie que les erreurs, comme celles que find pourrait gnrer, seront
affiches lcran, sans apparatre dans le fichier de tee. Pour enregistrer les erreurs,
vous pouvez ajouter 2>&1 la commande find :
find / -name '*.c' -print 2>&1 | tee /tmp/toutes.mes.sources

Elles ne seront pas spares de la sortie standard, mais elles seront au moins conserves.

Voir aussi

man tee ;

la recette 18.5, Rutiliser des arguments, page 480 ;

la recette 19.13, Dboguer des scripts, page 500.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.17. Connecter des programmes en utilisant la sortie comme argument

49

2.17. Connecter des programmes en utilisant la


sortie comme argument
Problme
Que pouvez-vous faire si lun des programmes connect par un tube ne fonctionne pas
selon ce principe ? Par exemple, vous pouvez supprimer des fichiers laide de la commande rm en les passant en paramtres :
$ rm mon.java votre.c leur.*

En revanche, puisque rm ne lit pas son entre standard, la ligne suivante ne fonctionnera pas :
find . -name '*.c' | rm

rm reoit les noms de fichiers uniquement via les arguments de la ligne de commande.
Comment la sortie dune commande prcdente (par exemple, echo ou ls) peut-elle
alors tre place sur la ligne de commande ?

Solution
Utilisez la substitution de commande de bash :
$ rm $(find . -name '*.class')
$

Discussion
$( ) englobe une commande excute dans un sous-shell. La sortie de cette commande
est mise la place de $( ). Les sauts de lignes prsents dans la sortie sont remplacs par
une espace (en ralit, le premier caractre de $IFS, qui, par dfaut, est une espace). Par
consquent, les diffrentes lignes de la sortie deviennent des paramtres sur la ligne de
commande.
Lancienne syntaxe du shell employait des apostrophes inverses (``) la place de $( ).
Cette nouvelle syntaxe est conseille car elle est plus facile imbriquer et, peut-tre, plus
facile lire. Cependant, vous rencontrerez `` probablement plus souvent que $( ), notamment dans les anciens scripts ou ceux crits par des personnes ayant connu les shells
Bourne ou C.
Dans notre exemple, la sortie de find, gnralement une liste de noms, est convertie en
arguments pour la commande rm.
Attention : soyez trs prudent lorsque vous utilisez cette possibilit car rm ne pardonne
pas. Si la commande find trouve dautres fichiers, en plus de ceux attendus, rm les supprimera sans vous laisser le choix. Vous ntes pas sous Windows ; vous ne pouvez rcuprer les fichiers supprims partir de la corbeille. La commande rm -i permet de
rduire les risques, en vous invitant valider chaque suppression. Si cette solution peut
tre envisage avec un petit nombre de fichiers, elle devient vite laborieuse ds quil
augmente.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

50

Chapitre 2 Sortie standard

Pour employer ce mcanisme dans bash avec de meilleures garanties, commencez par
excuter la commande interne. Si les rsultats obtenus vous conviennent, placez-la dans
la syntaxe $( ). Par exemple :
$ find . -name '*.class'
Premier.class
Autre.class
$ rm $(find . -name '*.class')
$

La recette 18.2, page 477, expliquera comment rendre ce mcanisme encore plus fiable,
en utilisant !! au lieu de saisir nouveau la commande find.

Voir aussi

la recette 15.13, Contourner les erreurs liste darguments trop longue , page 357 ;

la recette 18.2, Rpter la dernire commande, page 477.

2.18. Placer plusieurs redirections sur la mme


ligne
Problme
Vous souhaitez rediriger une sortie vers plusieurs destinations.

Solution
Utilisez une redirection avec des descripteurs de fichiers afin douvrir tous les fichiers
que vous souhaitez utiliser. Par exemple :
$ devier 3> fichier.trois 4> fichier.quatre 5> fichier.cinq 6> ailleurs
$

devier peut tre un script shell contenant diffrentes commandes dont les sorties doivent tre envoyes vers diffrentes destinations. Par exemple, vous pouvez crire un
script devier contenant des lignes de la forme echo option $OPTSTR >&5. Autrement
dit, devier peut envoyer sa sortie vers diffrents descripteurs, que le programme appelant peut rediriger vers diffrentes destinations.
De manire similaire, si devier est un programme C excutable, vous pourriez crire sur
les descripteurs de fichiers 3, 4, 5 et 6 sans passer par des appels open().

Discussion
La recette 2.8, page 39, a expliqu que chaque descripteur de fichier est indiqu par un
nombre, en commenant 0 (zro). Ainsi, lentre standard est le descripteur 0, la sortie
standard correspond au descripteur 1 et lerreur standard 2. Vous pouvez donc rediriger la sortie standard en utilisant 1> ( la place dun simple >) suivi dun nom de fichier,
mais ce nest pas obligatoire. La version abrge > convient parfaitement. Mais, cela si-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.19. Enregistrer la sortie lorsque la redirection semble inoprante

51

gnifie galement que le shell peut ouvrir un nombre quelconque de descripteurs de fichier et les associer diffrents fichiers, pour que le programme invoqu ensuite depuis
la ligne de commande puisse les utiliser.
Bien que nous ne recommandons pas cette technique, nous devons admettre quelle est
assez tonnante.

Voir aussi

la recette 2.6, Enregistrer la sortie vers dautres fichiers, page 37 ;

la recette 2.8, Envoyer la sortie et les erreurs vers des fichiers diffrents, page 39 ;

la recette 2.13, Oublier la sortie, page 43.

2.19. Enregistrer la sortie lorsque la redirection


semble inoprante
Problme
Vous essayez dutiliser > mais certains messages de sortie (voire tous) apparaissent encore lcran.
Par exemple, le compilateur produit des messages derreur :
$ gcc mauvais.c
mauvais.c: In function `main':
mauvais.c:3: error: `mauvais' undeclared (first use in this function)
mauvais.c:3: error: (Each undeclared identifier is reported only once
mauvais.c:3: error: for each function it appears in.)
mauvais.c:3: error: parse error before "c"
$

Vous souhaitez capturer ces messages et tentez donc de rediriger la sortie :


$ gcc mauvais.c > messages.erreur
mauvais.c: In function `main':
mauvais.c:3: error: `mauvais' undeclared (first use in this function)
mauvais.c:3: error: (Each undeclared identifier is reported only once
mauvais.c:3: error: for each function it appears in.)
mauvais.c:3: error: parse error before "c"
$

Malheureusement, cela ne semble pas fonctionner. En ralit, lorsque vous examinez le


fichier dans lequel la sortie est cense aller, vous constatez quil est vide :
$ ls -l messages.erreur
-rw-r--r-- 1 jp jp 0 2007-06-20 15:30 messages.erreur
$ cat messages.erreur
$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

52

Chapitre 2 Sortie standard

Solution
Redirigez la sortie derreur de la manire suivante :
$ gcc mauvais.c 2> messages.erreur
$

messages.erreur contient prsent les messages derreur qui taient affichs lcran.

Discussion
Que se passe-t-il donc ? Tout processus Unix ou Linux dmarre gnralement avec trois
descripteurs de fichier ouverts : un pour lentre standard (STDIN), un pour la sortie standard (STDOUT) et un pour les messages derreur, appel erreur standard (STDERR). Il
revient au programmeur de respecter ces conventions, autrement dit dcrire les messages derreur sur lerreur standard et la sortie normale sur la sortie standard. Cependant,
rien ne garantit que tous les messages derreur iront sur lerreur standard. La plupart des
utilitaires existants de longue date se comportent ainsi. Cest pourquoi les messages du
compilateur ne peuvent tre dvis par une simple redirection >. En effet, elle ne redirige que la sortie standard, non lerreur standard.
Chaque descripteur de fichier est indiqu par un nombre, en commenant 0. Lentre
standard est donc reprsente par 0, la sortie standard par 1 et lerreur standard par 2.
Cela signifie que vous pouvez donc rediriger la sortie standard en utilisant 1> ( la place
dun simple >) suivi dun nom de fichier, mais ce nest pas obligatoire. La version abrge > convient parfaitement.
Il existe une diffrence entre la sortie et lerreur standard. La premire utilise un tampon,
contrairement lerreur standard. Autrement dit, chaque caractre envoy sur lerreur
standard est crit individuellement et non mmoris puis crit comme un tout. Les
messages derreur sont affichs immdiatement, ce qui permet dviter leur perte en cas
de problmes, mais lefficacit sen trouve diminue. Nous ne prtendons pas que la sortie standard nest pas fiable, mais, dans des situations de dysfonctionnement (par exemple, un programme qui se termine de faon impromptue), le contenu du tampon risque
ne de pas arriver sur lcran avant la fin du programme. Cest la raison pour laquelle lerreur standard nutilise pas un tampon ; il faut que les messages soient affichs. En revanche, la sortie standard passe par un tampon. Les donnes sont crites uniquement
lorsque le tampon est plein ou que le fichier est ferm. Cette solution est plus efficace
pour une sortie frquemment sollicite. Cependant, lefficacit devient un aspect secondaire en cas derreurs.
Si vous souhaitez voir la sortie en cours denregistrement, utilisez la commande tee prsente la recette 2.16, page 47 :
$ gcc mauvais.c 2>&1 | tee messages.erreur

Lerreur standard est ainsi redirige vers la sortie standard, et toutes deux sont envoyes
tee. Cette commande crit son entre dans le fichier indiqu (messages.erreur), ainsi
que sur sa sortie standard, qui saffiche lcran puisquelle na pas t redirige.
Cette redirection est un cas particulier car lordre des redirections a normalement de
limportance. Comparez les deux commandes suivantes :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.20. Permuter STDERR et STDOUT

53

$ uneCommande >mon.fichier 2>&1


$ uneCommande 2>&1 >mon.fichier

Dans le premier cas, la sortie standard est redirige vers un fichier (mon.fichier) et lerreur standard est redirige vers la mme destination que la sortie standard. Les deux sorties apparaissent donc dans mon.fichier.
La deuxime commande fonctionne de manire diffrente. Lerreur standard est tout
dabord redirige vers la sortie standard (qui, ce stade, est associe lcran), puis la
sortie standard est envoye vers mon.fichier. Par consquent, seuls les messages de la
sortie standard sont placs dans le fichier, tandis que les erreurs apparaissent lcran.
Cependant, cet ordre doit tre invers pour les tubes. En effet, vous ne pouvez pas placer
la deuxime redirection aprs le symbole de tube, puisquaprs le tube vient la commande suivante. bash fait donc une exception lorsque vous crivez la ligne suivante et
reconnat que la sortie standard est dirige vers un tube :
$ uneCommande 2>&1 | autreCommande

Il suppose donc que 2>&1 signifie que vous souhaitez inclure lerreur standard dans le
tube, mme si lordre normal correspond un fonctionnement diffrent.
En consquence, dans un tube, il est impossible denvoyer uniquement lerreur standard, sans la sortie standard, vers une autre commande (cela est galement d la syntaxe des tubes en gnral). La seule solution consiste permuter les descripteurs de
fichiers, comme lexplique la recette suivante.

Voir aussi

la recette 2.17, Connecter des programmes en utilisant la sortie comme argument, page
49 ;

la recette 2.20, Permuter STDERR et STDOUT, page 53.

2.20. Permuter STDERR et STDOUT


Problme
Pour envoyer STDOUT dans un fichier et STDERR vers lcran et dans un fichier laide
de la commande tee, vous devez permuter STDERR et STDOUT. Cependant, les tubes
ne fonctionnent quavec STDOUT.

Solution
changez STDERR et STDOUT avant la redirection du tube en utilisant un troisime
descripteur de fichier :
$ ./monScript 3>&1 1>stdout.journal 2>&3- | tee -a stderr.journal

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

54

Chapitre 2 Sortie standard

Discussion
Lorsque vous redirigez des descripteurs de fichiers, vous dupliquez le descripteur ouvert
vers un second. Vous pouvez ainsi permuter des descripteurs, pratiquement de la mme
manire quun programme change deux valeurs, cest--dire au travers dun troisime
intermdiaire temporaire. Voici comment procder : copier A dans C, copier B dans A,
copier C dans B. Les valeurs de A et de B sont alors changes. Pour les descripteurs de
fichiers, lopration se passe de la manire suivante :
$ ./monScript 3>&1 1>&2 2>&3

La syntaxe 3>&1 signifie donner au descripteur de fichier 3 la mme valeur que le descripteur de fichier de sortie 1 . Plus prcisment, le descripteur de fichier 1(STDOUT) est
dupliqu dans le descripteur de fichier 3 (lintermdiaire). Ensuite, le descripteur de fichier 2 (STDERR) est dupliqu dans STDOUT. Enfin, le descripteur de fichier 3 est dupliqu
dans STDERR. Au final, vous changez les descripteurs de fichiers STDERR et STDOUT.
Nous devons prsent modifier lgrement cette opration. Une fois la copie de STDOUT
ralise (dans le descripteur de fichier 3), nous pouvons rediriger STDOUT dans le fichier
denregistrement de la sortie de notre script ou dun autre programme. Puis, nous pouvons copier le descripteur de fichier depuis lintermdiaire (le descripteur de fichier 3)
dans STDERR. Lajout du tube fonctionne car il est connect au STDOUT dorigine. Cela
conduit la solution propose prcdemment :
$ ./monScript 3>&1 1>stdout.journal 2>&3- | tee -a stderr.journal

Avez-vous remarqu le signe - la fin du terme 2>&3- ? Il permet de fermer le descripteur de fichier 3 lorsque nous nen avons plus besoin. Ainsi, notre programme ne laisse
pas de descripteur de fichier ouvert. Noubliez pas de fermer la porte en sortant.

Voir aussi

Administration Linux 200%, 1re dition, hack n5, n>&m : permuter sortie standard et erreur standard , de Rob Flickenger (ditions OReilly) ;

la recette 2.19, Enregistrer la sortie lorsque la redirection semble inoprante, page 51 ;

la recette 10.1, Convertir un script en dmon, page 207.

2.21. Empcher lcrasement accidentel des


fichiers
Problme
Vous ne souhaitez pas effacer par mgarde le contenu dun fichier. Il est trs facile de
mal orthographier un nom de fichier et de rediriger une sortie vers un fichier que vous
vouliez conserver.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.21. Empcher lcrasement accidentel des fichiers

55

Solution
Demandez au shell dtre plus prudent :
$ set -o noclobber
$

Si, par la suite, vous estimez quil est inutile dtre aussi prudent, dsactivez loption :
$ set +o noclobber
$

Discussion
Loption noclobber demande bash de ne pas craser un fichier existant lors de la redirection de la sortie. Si le fichier destinataire nexiste pas, tout se passe normalement :
bash cre le fichier lors de son ouverture pour y placer la sortie. En revanche, si le fichier
existe dj, vous recevez un message derreur.
En voici un exemple. Nous commenons par dsactiver loption, uniquement pour placer le shell dans un tat connu, quelle que soit la configuration initiale du systme.
$ set +o noclobber
$ echo quelquechose > mon.fichier
$ echo autre chose > mon.fichier
$ set -o noclobber
$ echo quelquechose > mon.fichier
bash: mon.fichier: cannot overwrite existing file
$ echo autre chose >> mon.fichier
$

Lors de la premire redirection de la sortie vers mon.fichier, le shell cre celui-ci. La


deuxime fois, bash crase le fichier (il le tronque 0 octet, puis crit partir du dbut).
Ensuite, nous fixons loption noclobber et recevons un message derreur lorsque nous
tentons dcrire dans le fichier. En revanche, il est possible dajouter du contenu au fichier (avec >>).
Attention ! Loption noclobber ne concerne que lcrasement dun
fichier lors de la redirection de la sortie au niveau du shell. Elle
nempche aucune autre suppression du fichier par dautres programmes (voir la recette 14.13, page 310).
$
$
$
$
$

echo donnes inutiles > un.fichier


echo donnes importantes > autre.fichier
set -o noclobber
cp un.fichier autre.fichier

Vous remarquerez que ces oprations ne dclenchent aucune erreur.


Le fichier est copi par dessus un fichier existant. La copie est ralise
avec la commande cp. Le shell nest pas impliqu.

Si vous faites trs attention lorsque vous saisissez les noms des fichiers, cette option peut
tre superf lue. Cependant, nous verrons, dans dautres recettes, des noms de fichiers g-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

56

Chapitre 2 Sortie standard

nrs par des expressions rgulires ou passs comme des variables. Ces noms peuvent
tre employs dans des redirections de sorties. Auquel cas, lactivation de loption noclobber apporte une certaine scurit et peut empcher certains effets secondaires indsirables (que ce soit par mgarde ou par volont de nuire).

Voir aussi

une bonne rfrence Linux sur la commande chmod et les autorisations des fichiers,
par exemple :
http://www.linuxforums.org/security/file_permissions.html ;
http://www.comptechdoc.org/os/linux/usersguide/linux_ugfilesup.html ;
http://www.faqs.org/docs/linux_intro/sect_03_04.html ;
http://www.perlfect.com/articles/chmod.shtml.

la recette 14.13, Fixer les autorisations, page 310.

2.22. craser un fichier la demande


Problme
Vous activez loption noclobber en permanence, mais, de temps autre, vous souhaitez
craser un fichier lors de la redirection dune sortie. Est-il possible de se soustraire occasionnellement la surveillance de bash ?

Solution
Utilisez >| pour rediriger la sortie. Mme si noclobber est active, bash lignore et crase
le fichier. Examinez lexemple suivant :
$ echo quelquechose > mon.fichier
$ set -o noclobber
$ echo autre chose >| mon.fichier
$ cat mon.fichier
autre chose
$ echo encore une fois > mon.fichier
bash: mon.fichier: cannot overwrite existing file
$

Vous remarquerez que la deuxime commande echo ne produit aucun message derreur,
contrairement la troisime dans laquelle la barre verticale (le tube) nest pas utilise.
Lorsque le caractre > est utilis seul, le shell vous avertit et ncrase pas le fichier existant.

Discussion
Loption noclobber noutrepasse pas les autorisations de fichier. Si vous ne possdez pas
le droit dcriture dans le rpertoire, vous ne pourrez crer le fichier, que vous utilisiez

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

2.22. craser un fichier la demande

57

ou non la construction >|. De manire similaire, vous devez avoir lautorisation dcriture sur le fichier lui-mme pour lcraser, avec ou sans >|.
Pourquoi une barre verticale ? Peut-tre parce que le point dexclamation tait dj utilis pour autre chose par bash et que la barre verticale est, visuellement, proche du point
dexclamation. Mais pourquoi le point dexclamation (!) serait-il le symbole appropri ?
Tout simplement parce quil marque une insistance. En franais (avec limpratif), il
pourrait vouloir dire bash fais-le, cest tout ! . Par ailleurs, lditeur vi (et ex) emploie galement ! dans le mme sens avec sa commande dcriture (:w! nomFichier).
Sans le !, il refuse dcraser un fichier existant. En lajoutant, vous dites lditeur vasy!

Voir aussi

la recette 14.13, Fixer les autorisations, page 310.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

3
Entre standard

Quelle contienne des donnes pour alimenter un programme ou de simples commandes pour paramtrer le comportement dun script, lentre est tout aussi fondamentale
que la sortie. La phase initiale de tout programme concerne la gestion des entres/sorties.

3.1. Lire les donnes dentre depuis un fichier


Problme
Vous souhaitez que vos commandes du shell lisent des donnes depuis un fichier.

Solution
Utilisez la redirection de lentre, symbolise par le caractre <, pour lire des donnes
depuis un fichier.
$ wc < mon.fichier

Discussion
Tout comme le symbole > envoie une sortie vers un fichier, le symbole < prend une entre depuis un fichier. Le choix des caractres apporte une information visuelle sur le
sens de la redirection.
Certaines commandes du shell attendent un ou plusieurs fichiers en argument, mais,
lorsquaucun nom nest prcis, elles se tournent vers lentre standard. Ces commandes
peuvent alors tre invoques sous la forme commande nomFichier ou commande < nomFichier,
avec le mme rsultat. Cet exemple illustre le cas de wc, mais cat et dautres commandes
oprent de la mme manire.
Cette fonctionnalit pourrait paratre secondaire et vous tre familire si vous avez dj
employ la ligne de commande du DOS, mais elle est en ralit trs importante pour
lcriture de scripts shell (que la ligne de commande du DOS a emprunt) et savre aussi puissante que simple.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

60

Chapitre 3 Entre standard

Voir aussi

la recette 2.6, Enregistrer la sortie vers dautres fichiers, page 37.

3.2. Conserver les donnes avec le script


Problme
Vous avez besoin de donnes dentre pour votre script, mais vous ne voulez pas quelles
soient dans un fichier spar.

Solution
Utilisez un here document, avec les caractres <<, en prenant le texte depuis la ligne de
commande et non depuis un fichier. Dans le cas dun script shell, le fichier du script contient les donnes ainsi que les commandes du script.
Voici un exemple de script shell plac dans un fichier nomm ext :
$ cat ext
#
# Voici le document en ligne.
#
grep $1 <<EOF
mike x.123
joe x.234
sue x.555
pete x.818
sara x.822
bill x.919
EOF
$

Il peut tre utilis comme un script shell qui recherche le numro de poste associ une
personne :
$ ext bill
bill x.919
$

ou linverse :
$ ext 555
sue x.555
$

Discussion
La commande grep recherche les occurrences de son premier argument dans les fichiers
nomms ou sur lentre standard. Voici les utilisations classiques de grep :
$ grep uneChane fichier.txt
$ grep maVar *.c

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

3.3. Empcher un comportement trange dans un here document

61

Dans notre script ext, nous avons paramtr la commande grep en lui indiquant que la
chane recherche est un argument du script shell ($1). Mme si grep est souvent employe pour rechercher une certaine chane dans plusieurs fichiers diffrents, dans notre exemple, la chane recherche varie alors que les donnes de recherche sont figes.
Nous pourrions placer les numros de tlphone dans un fichier, par exemple
numeros.txt et lutiliser lors de linvocation de la commande grep :
grep $1 numeros.txt

Cependant, cette approche exige deux fichiers distincts (le script et le fichier des donnes). Se pose alors la question de leur emplacement et de leur stockage conjoint.
Au lieu dindiquer un ou plusieurs noms de fichiers (dans lesquels se fait la recherche),
nous prparons un document en ligne et indiquons au shell de rediriger lentre standard vers ce document (temporaire).
La syntaxe << prcise que nous voulons crer une source dentre temporaire et le marqueur EOF nest quune chane quelconque (vous pouvez en choisir une autre) qui joue
le rle dindicateur de fin de lentre temporaire. Elle nest pas incluse dans lentre,
mais signale uniquement l o lentre sarrte. Le script shell normal reprend aprs le
marqueur.
En ajoutant loption -i la commande grep, la recherche ne tient plus compte de la casse. Ainsi, la commande grep -i $1 <<EOF nous permettrait deffectuer la recherche sur
Bill aussi bien que sur bill .

Voir aussi

man grep ;

la recette 3.3, Empcher un comportement trange dans un here document, page 61 ;

la recette 3.4, Indenter un here document, page 63.

3.3. Empcher un comportement trange dans


un here document
Problme
Votre here document1 se comporte bizarrement. Vous essayez de grer une simple liste
de donateurs en utilisant la mthode dcrite prcdemment pour les numros de tlphone. Vous avez donc cr un fichier nomm donateurs :
$ cat donateurs
#
# Simple recherche de nos gnreux donateurs.
#

1. N.d.T. : Un here document permet de saisir un ensemble de lignes avant de les envoyer sur
lentre standard dune commande.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

62

Chapitre 3 Entre standard


grep $1 <<EOF
# nom montant
pete $100
joe $200
sam $ 25
bill $ 9
EOF
$

Mais son excution produit une sortie trange :


$ ./donateurs bill
pete bill00
bill $ 9
$ ./donateurs pete
pete pete00
$

Solution
Dsactivez les fonctionnalits des scripts shell dans le here document en appliquant
lchappement un ou tous les caractres du marqueur de fin :
# solution
grep $1 <<\EOF
pete $100
joe $200
sam $ 25
bill $ 9
EOF

Discussion
La diffrence est subtile, mais <<EOF a t remplac par <<\EOF. Vous pouvez galement
utiliser <<'EOF' ou mme <<E\OF. Cette syntaxe nest pas la plus lgante, mais elle suffit
indiquer bash que les donnes en ligne doivent tre traites diffremment.
La page de manuel de bash indique que, normalement (cest--dire sans lchappement),
... toutes les lignes du here document sont assujetties lexpansion des paramtres,
la substitution de commandes et lexpansion arithmtique .
Par consquent, dans la premire version du script donateurs, les montants sont considrs comme des variables du shell. Par exemple, $100 est trait comme la variable $1 suivi
de deux zros. Cest pourquoi nous obtenons pete00 lorsque nous recherchons pete
et bill00 pour bill .
Lorsque lchappement est appliqu un ou plusieurs caractres de EOF, bash sait quil
ne doit pas effectuer dexpansion et le comportement est alors celui attendu :
$ ./donateurs pete
pete $100
$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

3.4. Indenter un here document

63

Vous voudrez parfois que lexpansion du shell sapplique vos donnes, mais ce nest pas
le cas ici. Nous estimons quil est prfrable de toujours appliquer lchappement au
marqueur, comme dans <<'EOF' ou <<\EOF, afin dviter les rsultats inattendus. Lorsque lexpansion doit concerner vos donnes, indiquez-le explicitement en retirant
lchappement.
Si le marqueur EOF est suivi despaces, mme une seule, il nest plus
reconnu comme le marqueur de fin. bash absorbe alors la suite du
script comme des donnes dentre et continue sa recherche de EOF.
Vous devez donc vrifier trs soigneusement quaucun caractre,
notamment des espaces ou des tabulations, ne se trouve aprs EOF.

Voir aussi

la recette 3.2, Conserver les donnes avec le script, page 60 ;

la recette 3.4, Indenter un here document, page 63.

3.4. Indenter un here document


Problme
Le here document fonctionne parfaitement, mais il souille la parfaite mise en forme de
votre script shell. Vous voulez pouvoir lindenter afin de conserver la lisibilit.

Solution
Utilisez <<-. Vous pourrez ensuite employer des caractres de tabulation (uniquement)
au dbut des lignes pour indenter cette partie du script :
$ cat monScript.sh
...
grep $1 <<-'EOF'
Cette partie du script
contient beaucoup de donnes.
Elle est donc indente avec des
tabulations afin de respecter
lindentation du script. Les
tabulations en dbut de ligne
sont supprimes lors de
la lecture.
EOF
ls
...
$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

64

Chapitre 3 Entre standard

Discussion
Le tiret plac juste aprs << indique bash quil doit ignorer les caractres de tabulation
placs en dbut de ligne. Cela ne concerne que les caractres tab et non un caractre despacement quelconque. Ce point est particulirement important avec EOF ou tout autre
marqueur. Si le dbut de ligne contient des espaces, EOF nest pas reconnu comme le
marqueur de fin et les donnes en ligne vont jusqu la fin du fichier (le reste du script
est ignor). Par consquent, vous pouvez, pour plus de scurit, toujours aligner gauche EOF (ou tout autre marqueur) et retirer la mise en forme de cette ligne.
Tout comme les espaces places aprs le marqueur EOF lempchent
dtre reconnu comme la fin des donnes en ligne (voir lavertissement
de la recette 3.3, page 61), tout caractre initial autre quune tabulation
provoquera le mme dysfonctionnement. Si votre script base son
indentation sur des espaces ou une combinaison despaces et de tabulations, nemployez pas cette solution avec les here documents. Vous
devez utiliser uniquement des tabulations ou aucun caractre. Par
ailleurs, mfiez-vous des diteurs de texte qui remplacent automatiquement les tabulations par des espaces.

Voir aussi

la recette 3.2, Conserver les donnes avec le script, page 60 ;

la recette 3.3, Empcher un comportement trange dans un here document, page 61.

3.5. Lire lentre de lutilisateur


Problme
Vous devez obtenir des donnes dentre de la part de lutilisateur.

Solution
Utilisez linstruction read :
read

ou :
read p "merci de rpondre " REPONSE

ou :
read AVANT MILIEU APRES

Discussion
Dans sa forme la plus simple, une instruction read sans argument lit lentre de lutilisateur et la place dans la variable REPLY.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

3.6. Attendre une rponse Oui ou Non

65

Si vous souhaitez que bash affiche une invite avant la lecture de lentre, ajoutez loption
-p. Le mot plac aprs -p devient linvite, mais lutilisation des guillemets vous permet
de passer une chane plus longue. Noubliez pas de terminer linvite par un symbole de
ponctuation et/ou une espace, car le curseur attendra lentre juste aprs la fin de la
chane dinvite.
Si vous prcisez plusieurs noms de variables dans linstruction read, lentre est dcompose en mots, qui sont affectes dans lordre aux variables. Si lutilisateur saisit moins
de mots quil y a de variables, les variables supplmentaires sont vides. Sil le nombre de
mots est suprieur au nombre de variables dans linstruction read, les mots supplmentaires sont placs dans la dernire variable de la liste.

Voir aussi

help read ;

la recette 3.8, Demander un mot de passe, page 69 ;

la recette 6.11, Boucler avec read, page 133 ;

la recette 13.6, Analyser du texte avec read, page 266 ;

la recette 14.12, Valider lentre, page 308.

3.6. Attendre une rponse Oui ou Non


Problme
Vous voulez que lutilisateur rponde simplement Oui ou Non, tout en offrant la
meilleure interface possible. En particulier, la casse ne doit pas tre prise en compte et
une valeur par dfaut doit tre choisie si lutilisateur appuie sur la touche Entre sans
rpondre.

Solution
Si les actions raliser sont simples, servez-vous de la fonction suivante :
# bash Le livre de recettes : fonction_choisir
# Laisse l'utilisateur faire un choix et excute le code selon sa rponse.
# Utilisation : choisir <dfaut (o ou n)> <invite> <action oui> <action non>
# Par exemple :
#
choisir "o" \
#
"Voulez-vous jouer ce jeu ?" \
#
/usr/games/GuerreThermonucleaireMondiale \
#
'printf "%b" "Au revoir Professeur Falkin."' >&2
# Retour : aucune
function choisir {
local defaut="$1"
local invite="$2"

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

66

Chapitre 3 Entre standard


local choix_oui="$3"
local choix_non="$4"
local reponse
read -p "$invite" reponse
[ -z "$reponse" ] && reponse="$defaut"
case "$reponse" in
[oO1] ) exec "$choix_oui"
# Contrle d'erreurs.
;;
[nN0] ) exec "$choix_non"
# Contrle d'erreurs.
;;
*
) printf "%b" "Rponse inattendue '$reponse'!" >&2 ;;
esac
} # Fin de la fonction choisir.

Si les actions sont complexes, utilisez la fonction suivante et traitez la rponse dans le
code principal :
# bash Le livre de recettes : fonction_choisir.1
# Laisse l'utilisateur faire un choix et retourne une rponse standardise.
# La prise en charge de la rponse par dfaut et des actions ultrieures
# sont dfinir dans la section if/then qui se trouve aprs le choix
# dans le code principal.
# Utilisation : choisir <invite>
# Exemple : choisir "Voulez-vous jouer ce jeu ?"
# Retour : variable globale CHOIX
function choisir {
CHOIX=''
local invite="$*"
local reponse
read -p "$invite" reponse
case "$reponse" in
[oO1] ) CHOIX='o';;
[nN0] ) CHOIX='n';;
*
) CHOIX="$reponse";;
esac
} # Fin de la fonction choisir.

Le code suivant invoque la fonction choisir pour inviter lutilisateur entrer la date
dun paquet et la vrifier. Si lon suppose que la variable $CEPAQUET contient une valeur,
la fonction affiche la date et demande son approbation. Si lutilisateur tape o, O ou Entre, la date est accepte. Sil saisit une nouvelle date, la fonction boucle et repose la
question (la recette 11.7, page 233, propose une autre manire de traiter ce problme) :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

3.6. Attendre une rponse Oui ou Non

67

# bash Le livre de recettes : fonction_choisir.2


until [ "$CHOIX" = "o" ]; do
printf "%b" "La date de ce paquet est $CEPAQUET\n" >&2
choisir "Est-ce correct ? [O/,<Nouvelle date>] : "
if [ -z "$CHOIX" ]; then
CHOIX='o'
elif [ "$CHOIX" != "o" ]; then
printf "%b" "$CEPAQUET est remplac par ${CHOIX}\n"
CEPAQUET=$CHOIX
fi
done
# Compiler le paquet ici.

Nous allons maintenant examiner deux manires diffrentes de traiter certaines questions de type oui ou non . Faites bien attention aux invites et aux valeurs par dfaut.
Dans les deux cas, lutilisateur peut simplement appuyer sur la touche Entre et le script
prend alors la valeur par dfaut fixe par le programmeur.
# Si lutilisateur saisit autre chose que le caractre 'n', quelle que
# soit sa casse, le journal des erreurs est affich.
choisir "Voulez-vous examiner le journal des erreurs ? [O/n] : "
if [ "$CHOIX" != "n" ]; then
less error.log
fi
# Si lutilisateur saisit autre chose que le caractre 'y', quelle que
# soit sa casse, le journal des erreurs nest pas affich.
choisir "Voulez-vous examiner le journal des erreurs ? [o/N] : "
if [ "$CHOIX" = "o" ]; then
less message.log
fi

Enfin, la fonction suivante accepte une entre qui peut ne pas exister :
# bash Le livre de recettes : fonction_choisir.3
choisir "Entrez votre couleur prfre, si vous en avez une : "
if [ -n "$CHOIX" ]; then
printf "%b" "Vous avez choisi : $CHOIX"
else
printf "%b" "Vous n'avez pas de couleur prfre."
fi

Discussion
Dans les scripts, vous aurez souvent besoin de demander lutilisateur de faire un choix.
Pour une rponse arbitraire, consultez la recette 3.5, page 64. Si le choix doit se faire dans
une liste doptions, consultez la recette 3.7, page 68.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

68

Chapitre 3 Entre standard

Si les choix possibles et leur code de traitement sont assez simples, la premire fonction
sera plus facile utiliser, mais elle nest pas trs souple. La deuxime fonction est plus
adaptable mais exige un travail plus important dans le code principal.
Vous remarquerez que les invites sont affiches sur STDERR. Ainsi, la sortie effectue
sur STDOUT par le script principal peut tre redirige sans que les invites sy immiscent.

Voir aussi

la recette 3.5, Lire lentre de lutilisateur, page 64 ;

la recette 3.7, Choisir dans une liste doptions, page 68 ;

la recette 11.7, Calculer avec des dates et des heures, page 233.

3.7. Choisir dans une liste doptions


Problme
Vous devez fournir lutilisateur une liste doptions parmi laquelle il doit faire son
choix, mais vous souhaitez un minimum de saisie.

Solution
Utilisez la construction select de bash pour gnrer un menu, puis laissez lutilisateur
faire son choix en entrant le numro correspondant :
# bash Le livre de recettes : selection_rep
listerep="Quitter $(ls /)"
PS3='Rpertoire analyser ? ' # Invite de slection.
until [ "$repertoire" == "Quitter" ]; do
printf "%b" "\a\n\nSlectionnez le rpertoire analyser :\n" >&2
select repertoire in $listerep; do
# L'utilisateur tape un nombre, qui est stock dans $REPLY, mais
# select retourne la valeur de l'entre.
if [ "$repertoire" = "Quitter" ]; then
echo "Analyse des rpertoires termine."
break
elif [ -n "$repertoire" ]; then
echo "Vous avez choisi le numro $REPLY,"\
"analyse de $repertoire..."
# Faire quelque chose.
break
else
echo "Slection invalide !"
fi # Fin du traitement du choix de l'utilisateur.
done # Fin de la slection d'un rpertoire.
done # Fin de la boucle while non termine.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

3.8. Demander un mot de passe

69

Discussion
Grce la fonction select, il est extrmement facile de prsenter une liste numrote
lutilisateur sur STDERR et partir de laquelle il pourra faire son choix. Noubliez pas
loption Quitter .
Le numro entr par lutilisateur se trouve dans la variable $REPLY et la valeur de lentre est retourne dans la variable indique dans la construction select.

Voir aussi

help select ;

help read ;

la recette 3.6, Attendre une rponse Oui ou Non, page 65.

3.8. Demander un mot de passe


Problme
Vous devez demander un mot de passe un utilisateur, mais sans quil soit affich
lcran.

Solution
read -s -p "mot de passe : " MOTDEPASSE
printf "%b" "\n"

Discussion
Loption -s demande la commande read de ne pas afficher les caractres saisis (s comme silence) et loption -p signale que largument suivant reprsente linvite afficher
avant de lire lentre.
Les donnes saisies par lutilisateur sont places dans la variable denvironnement $MOTDEPASSE.
Aprs read, nous ajoutons une instruction printf afin dafficher un saut de ligne.
printf est ncessaire car read -s inactive la rptition des caractres saisis et aucun saut
de ligne nest donc affich lorsque lutilisateur appuie sur la touche Entre ; toute sortie
suivante apparatra sur la mme ligne que linvite. Vous pouvez crire ce code sur une
seule ligne pour que le lien entre les deux instructions soit bien clair. Cela vite galement les erreurs si vous devez copier et coller cette ligne ailleurs :
read -s -p "mot de passe : " MOTDEPASSE ; printf "%b" "\n"

Si vous placez le mot de passe dans une variable denvironnement, vous ne devez pas
oublier quil se trouve en clair en mmoire et quil peut donc tre obtenu par un vidage
de la mmoire (core dump) ou en consultant /proc/core. Il se trouve galement dans lenvironnement du processus, auquel dautres processus peuvent accder. Il est prfrable

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

70

Chapitre 3 Entre standard

demployer des certificats avec SSH. Dans tous les cas, il est plus prudent de supposer
que root et dautres utilisateurs de la machine peuvent accder au mot de passe et donc
de traiter le cas de manire approprie.
Certains scripts anciens peuvent utiliser s pour dsactiver laffichage
lcran pendant la saisie dun mot de passe. Cette solution prsente un
inconvnient majeur : si lutilisateur interrompt le script, laffichage
des caractres reste dsactiv. Les utilisateurs expriments sauront excuter stty sane pour corriger le problme, mais cest assez perturbant. Si vous devez employer cette mthode, mettez en place une gestion des signaux afin de ractiver laffichage lorsque le script se termine
(voir la recette 10.6, page 215).

Voir aussi

help read ;

la recette 10.6, Intercepter les signaux, page 215 ;

la recette 14.14, Afficher les mots de passe dans la liste des processus, page 311 ;

la recette 14.20, Utiliser des mots de passe dans un script, page 319 ;

la recette 14.21, Utiliser SSH sans mot de passe, page 321 ;

la recette 19.9, Rinitialiser le terminal, page 496.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

4
Excuter des commandes

Le premier objectif de bash (comme de nimporte quel interprteur de commandes) est


de vous laisser interagir avec le systme dexploitation de lordinateur afin deffectuer
votre travail. En gnral, cela implique le lancement de programmes. Le shell rcupre
donc les commandes que vous avez saisies, les analyse pour dterminer les programmes
excuter et lance ceux-ci.
Examinons le mcanisme de base du lancement des programmes et explorons les possibilits offertes par bash, comme lexcution des programmes au premier ou larrireplan, squentiellement ou en parallle, avec une indication de la russite ou de lchec
des programmes, et dautres.

4.1. Lancer nimporte quel excutable


Problme
Vous voulez excuter une commande sur un systme Linux ou Unix.

Solution
Utilisez bash et saisissez le nom de la commande linvite.
$ unProgramme

Discussion
Cela semble plutt simple et, en un certain sens, cest effectivement le cas, mais, en coulisses, il se passe de nombreuses choses que vous ne verrez jamais. Limportant est de
bien comprendre que le travail fondamental de bash est de charger et dexcuter des programmes. Tout le reste nest quun habillage autour de cette fonction. Il existe bien sr
les variables du shell, les instructions for pour les boucles et if/then/else pour les branchements, ainsi que diffrents mcanismes de gestion des entres et des sorties, mais
tout cela nest en ralit quun dcor.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

72

Chapitre 4 Excuter des commandes

O bash trouve-t-il le programme excuter ? Pour trouver lexcutable que vous avez
indiqu, il utilise une variable du shell appele $PATH. Cette variable contient une liste
de rpertoires spars par des deux-points (:). bash recherche dans chacun de ces rpertoires un fichier correspondant au nom prcis. Lordre des rpertoires est important.
bash les examine dans leur ordre dapparition dans la variable et prend le premier excutable trouv.
$ echo $PATH
/bin:/usr/bin:/usr/local/bin:.
$

La variable $PATH prcdente contient quatre rpertoires. Le dernier de la liste est juste
un point (appel rpertoire point ou simplement point), qui reprsente le rpertoire de
travail. Le point est le nom dun rpertoire qui se trouve dans chaque rpertoire dun
systme de fichiers Linux ou Unix ; quel que soit lendroit o vous vous trouvez, le
point fait rfrence ce rpertoire. Par exemple, si vous copiez un fichier depuis un rpertoire vers le rpertoire point (cest--dire cp /autre/endroit/fichier .), vous copiez
en ralit le fichier dans le rpertoire en cours. En plaant le rpertoire point dans la
variable $PATH, bash recherche non seulement les commandes dans les autres rpertoires, mais galement dans le rpertoire de travail (.).
Certains considrent que lajout du rpertoire point dans la variable $PATH constitue un
un risque de scurit important. En effet, une personne pourrait vous duper et vous faire excuter sa propre version (nuisible) dune commande la place de celle suppose.
Si ce rpertoire arrive en tte de la liste, la version de ls propre cette personne supplante la commande ls et cest elle que vous excuterez, sans le savoir. Pour vous en rendre
compte, testez le code suivant :
$
$
$
$
$
$
$

bash
cd
touch ls
chmod 755 ls
PATH=".:$PATH"
ls

La commande ls semble ne plus fonctionner dans votre rpertoire personnel. Elle ne


produit aucune sortie. Lorsque vous passez dans un autre rpertoire, par exemple cd
/tmp, ls fonctionne nouveau. Pourquoi ? Dans votre rpertoire personnel, cest le fichier vide appel ls qui est excut (il ne fait rien) la place de la commande ls normale
qui se trouve dans /bin. Puisque, dans notre exemple, nous commenons par lancer une
nouvelle copie de bash, vous pouvez quitter cet environnement sabot en sortant du
sous-shell. Mais avant cela, noubliez pas de supprimer la commande ls invalide :
$ cd
$ rm ls
$ exit
$

Vous pouvez facilement imaginer le potentiel malfaisant dune recherche dans le rpertoire point avant tous les autres.
Lorsque le rpertoire point se trouve la fin de la variable $PATH, vous ne pourrez pas
tre tromp aussi facilement. Si vous len retirez totalement, vous tes plus en scurit

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

4.2. Connatre le rsultat de lexcution dune commande

73

et vous pouvez toujours excuter les commandes du rpertoire courant en les prfixant
par ./ :
$ ./monScript

Cest vous de dcider.


Vous ne devez jamais placer le rpertoire point ou des rpertoires
modifiables dans la variable $PATH de root. Pour plus dinformations,
consultez les recettes 14.9, page 300, et 14.10, page 303.

Noubliez pas de fixer les autorisations dexcution des fichiers avant dinvoquer le
script :
$ chmod a+x ./monScript
$ ./monScript

Cette opration ne doit tre effectue quune seule fois. Ensuite, vous pouvez invoquer
le script comme nimporte quelle commande.
Les experts bash crent souvent un rpertoire bin personnel, analogue aux rpertoires
systme /bin et /usr/bin qui contiennent les programmes excutables. Dans votre bin personnel, vous pouvez placer des copies de vos scripts shell prfrs, ainsi que dautres
commandes personnalises ou prives. Ensuite, ajoutez votre rpertoire personnel
$PATH, mme en dbut de liste (PATH=~/bin:$PATH). De cette manire, vous avez accs
vos commandes prfres sans risque dexcuter celles dautres personnes potentiellement malveillantes.

Voir aussi

le chapitre 16, Configurer bash, page 367, pour plus dinformations sur la personnalisation de votre environnement ;

la recette 1.3, Chercher et excuter des commandes, page 6 ;

la recette 14.9, Trouver les rpertoires modifiables mentionns dans $PATH, page 300 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303 ;

la recette 16.9, Crer son rpertoire priv dutilitaires, page 389 ;

la recette 19.1, Oublier les autorisations dexcution, page 485.

4.2. Connatre le rsultat de lexcution dune


commande
Problme
Vous voulez savoir si la commande que vous avez excute a russi ou chou.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

74

Chapitre 4 Excuter des commandes

Solution
La variable $? du shell contient une valeur diffrente de zro si la commande a chou,
mais condition que le programmeur qui a crit la commande ou le script shell ait respect les conventions tablies :
$ uneCommande
jai russi...
$ echo $?
0
$ commandeInvalide
jai chou...
$ echo $?
1
$

Discussion
Ltat de sortie dune commande est plac dans la variable $? du shell. Sa valeur se trouve
dans lintervalle 0 255. Lorsque vous crivez un script shell, nous vous conseillons de
le faire se terminer avec une valeur diffrente de zro en cas derreur (elle doit tre infrieure 255). Pour retourner un code dtat de sortie, utilisez linstruction exit (par
exemple, exit 1 ou exit 0). Cependant, vous devez savoir que ltat de la sortie ne peut
tre lu une seule fois :
$ commandeInvalide
jai chou...
$ echo $?
1
$ echo $?
0
$

Pourquoi obtenons-nous 0 la deuxime fois ? Tout simplement parce que la variable indique alors ltat de sortie de la commande echo qui prcde. La premire commande
echo $? a retourn 1, cest--dire ltat de sortie de commandeInvalide. Cette commande
echo sest parfaitement droule et ltat de sortie le plus rcent correspond donc un
succs (la valeur 0). Puisque vous navez quune seule occasion de le consulter, de nombreux scripts shell affectent immdiatement ltat de sortie une autre variable :
$ commandeInvalide
jai chou...
$ ETAT=$?
$ echo $ETAT
1
$ echo $ETAT
1
$

Vous pouvez conserver la valeur dans la variable $ETAT aussi longtemps que ncessaire.
Nous illustrons ce fonctionnement dans des exemples en ligne de commande, mais les
variables comme $? sont, en ralit, plus utiles dans les scripts. Vous pouvez toujours
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

4.3. Excuter plusieurs commandes la suite

75

savoir si une commande sest bien droule en regardant votre cran. En revanche, dans
un script, les commandes peuvent avoir des comportements inattendus.
bash a pour avantage dutiliser un langage de scripts identique aux commandes saisies
au niveau de linvite dans une fentre de terminal. Il est ainsi beaucoup plus facile de
vrifier une syntaxe et une logique pendant lcriture de scripts.
Ltat de sortie est trs souvent employ dans les scripts, principalement dans des instructions if, pour effectuer des actions diffrentes selon le succs ou lchec dune commande. Voici un exemple simple sur lequel nous reviendrons dans dautres recettes :
$ uneCommande
...
$ if (( $? )) ; then echo chec ; else echo OK; fi

Voir aussi

la recette 4.5, Dterminer le succs dune commande, page 77 ;

la recette 4.8, Afficher des messages en cas derreur, page 80 ;

la recette 6.2, Conditionner lexcution du code, page 116.

4.3. Excuter plusieurs commandes la suite


Problme
Vous souhaitez excuter plusieurs commandes, mais certaines prennent beaucoup de
temps et vous ne voulez pas attendre quelles se terminent avant de lancer les suivantes.

Solution
Ce problme a trois solutions, mme si la premire est plutt triviale : il suffit de les saisir. Un systme Linux ou Unix est suffisamment labor pour vous permettre de saisir
des commandes pendant quil excute les prcdentes. Vous pouvez donc simplement
saisir toutes les commandes lune aprs lautre.
Une autre solution galement simple consiste placer ces commandes dans un fichier
et de demander ensuite bash de les excuter. Autrement dit, vous crivez un script
shell simple.
Supposons que vous vouliez excuter trois commandes : long, moyen et court, dont les
noms refltent leur temps dexcution. Vous devez les excuter dans cet ordre, mais
vous ne voulez pas attendre que long soit termine avant dinvoquer les autres commandes. Vous pouvez utiliser un script shell (ou fichier batch), de la manire la plus simple
qui soit :
$ cat > simple.script
long
moyen
court
^D
# Ctrl-D, non visible.
$ bash ./simple.script

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

76

Chapitre 4 Excuter des commandes

La troisime solution, probablement la meilleure, consiste excuter chaque commande la suite. Si vous voulez lancer tous les programmes, mme si le prcdent a chou,
sparez-les par des points-virgules sur la mme ligne de commande :
$ long ; moyen ; court

Pour excuter un programme uniquement si le prcdent sest bien pass (et sils grent
tous correctement leur code de sortie), sparez-les par deux esperluettes :
$ long && moyen && court

Discussion
Lexemple de cat nest quune solution trs primitive dentre du texte dans la fichier.
Nous redirigeons la sortie de la commande vers le fichier nomm simple.script (la redirection de la sortie est explique au chapitre 2). La meilleure solution consiste employer un vritable diteur de texte, mais il est plus difficile de la reprsenter sur de tels
exemples. partir de maintenant, lorsque nous voudrons montrer un script, nous donnerons uniquement le texte en dehors de la ligne de commande ou dbuterons lexemple par une commande de la forme cat nomFichier pour envoyer le contenu du fichier
lcran (au lieu de rediriger la sortie de notre saisie vers le fichier) et donc lafficher
dans lexemple.
Cette solution simple a pour objectif de montrer quil est possible de placer plusieurs
commandes sur la ligne de commande de bash. Dans le premier cas, la deuxime commande nest excute quune fois la premire termine, la deuxime nest excute
quune fois la troisime termine, etc. Dans le second cas, la deuxime commande nest
lance que si la premire sest termine avec succs, la troisime que si la deuxime sest
termine avec succs, etc.

4.4. Excuter plusieurs commandes la fois


Problme
Vous souhaitez excuter trois commandes indpendantes les unes des autres et ne voulez pas attendre que lune se termine avant de passer la suivante.

Solution
Excutez les commandes en arrire-plan en ajoutant une esperluette (&) la fin de la
ligne. Vous pouvez ainsi dmarrer les trois tches la fois :
$ long &
[1] 4592
$ moyen &
[2] 4593
$ court
$

Mieux encore, placez-les toutes sur la mme ligne de commande :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

4.5. Dterminer le succs dune commande

77

$ long & moyen & court


[1] 4592
[2] 4593
$

Discussion
Lorsquune commande sexcute en arrire-plan, cela signifie en ralit que le clavier est
dtach de lentre de la commande et que le shell nattend pas quelle se termine pour
rendre la main et accepter dautres commandes. La sortie de la commande est toujours
envoye lcran (except si vous avez indiqu un comportement diffrent). Par consquent, les trois tches verront leur sortie mlange lcran.
Les valeurs numriques affiches correspondent au numro de la tche (entre les crochets) et lidentifiant du processus de la commande dmarre en arrire-plan. Dans
cet exemple, la tche 1 (processus 4592) correspond la commande long et la tche 2
(processus 4593) moyen.
La commande court ne sexcute pas en arrire-plan car nous navons pas ajout une esperluette la fin de la ligne. bash attend quelle se termine avant de revenir linvite (le
caractre $).
Le numro de tche et lidentifiant de processus peuvent tre utiliss pour agir, de manire limite, sur la tche. La commande kill %1 arrte lexcution de long (puisque son
numro de job est 1). Vous pouvez galement indiquer son numro de processus (kill
4592) pour obtenir le mme rsultat final.
Le numro de tche peut galement servir replacer la commande correspondante au
premier plan. Pour cela, utilisez la commande fg %1. Si une seule tche sexcute en arrire-plan, son numro est mme inutile, il suffit dinvoquer fg.
Si vous lancez un programme et ralisez ensuite quil prend plus de temps que vous le
pensiez, vous pouvez le suspendre avec Ctrl-Z ; vous revenez alors linvite. La commande bg poursuit lexcution du programme en arrire-plan. Cela quivaut ajouter
& lors du lancement de la commande.

Voir aussi

le chapitre 2, Sortie standard, page 31, pour la redirection de la sortie.

4.5. Dterminer le succs dune commande


Problme
Vous souhaitez excutez certaines commandes, mais uniquement si dautres ont russi.
Par exemple, vous voulez changer de rpertoire (avec cd) et supprimer tous les fichiers
quil contient. Cependant, les fichiers ne doivent pas tre supprims si la commande cd
a chou (par exemple, si les permissions ne vous autorisent pas aller dans le rpertoire ou si son nom a t mal crit).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

78

Chapitre 4 Excuter des commandes

Solution
Vous pouvez combiner ltat de sortie ($?) de la commande cd et une instruction if
pour effectuer la suppression (commande rm) uniquement si cd sest bien passe.
cd monTmp
if (( $? )); then rm * ; fi

Discussion
Bien videmment, tout cela ne serait pas ncessaire si les commandes taient effectues
la main. Vous verriez alors les messages derreur produits par la commande cd et dcideriez de ne pas excuter la commande rm. Dans un script, les choses sont diffrentes.
Le test est indispensable pour vrifier que vous nallez pas effacer par mgarde tous les
fichiers du rpertoire de travail.
Supposons que vous invoquiez ce script partir dun mauvais rpertoire, cest--dire un
rpertoire qui nait pas de sous-rpertoire monTmp. La commande cd choue donc et le
rpertoire courant reste le mme. Sans linstruction if, qui vrifie si cd a russi, le script
se poursuit avec la ligne suivante. Lexcution de rm * supprime alors tous les fichiers
du rpertoire courant. Mieux vaut ne pas oublier le test avec if !
Do la variable $? obtient-elle sa valeur ? Il sagit du code de sortie de la commande.
Les programmeurs C y verront la valeur donne largument de la fonction exit() ;
par exemple, exit(4); affectera la valeur 4 cette variable. Vis--vis du shell, 0 reprsente un succs et une autre valeur indique un chec.
Si vous crivez des scripts bash, vous devez absolument vrifier quils fixent leur valeur
de retour. Ainsi, $? sera correctement affecte par vos scripts. Dans le cas contraire, la
valeur donne cette variable sera celle de la dernire commande excute, ce qui ne
donnera peut-tre pas le rsultat escompt.

Voir aussi

la recette 4.2, Connatre le rsultat de lexcution dune commande, page 73 ;

la recette 4.6, Utiliser moins dinstructions if, page 78.

4.6. Utiliser moins dinstructions if


Problme
En tant que programmeur consciencieux, vous avez cur de suivre les recommandations donnes la recette 4.5, page 77. Vous appliquez le concept prsent votre dernier
script shell, mais il devient illisible cause de toutes ces instructions if qui vrifient le
code de retour de chaque commande. Existe-t-il une autre solution ?

Solution
Utilisez loprateur double esperluette de bash pour dfinir une excution conditionnelle :
$ cd monTmp && rm *

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

4.7. Lancer de longues tches sans surveillance

79

Discussion
En sparant deux commandes par une double esperluette, vous demandez bash dexcuter la premire commande, puis la seconde uniquement si la premire a russi (si son
tat de sortie vaut 0). Cela quivaut une instruction if qui vrifie le code de sortie de
la premire commande afin de conditionner lexcution de la seconde :
cd monTmp
if (( $? )); then rm * ; fi

La syntaxe de la double esperluette provient de loprateur logique ET du langage C. Si


vous navez pas oubli votre cours de logique, vous devez savoir que lvaluation de lexpression logique A ET B ne sera vraie que si les deux (sous-)expressions A et B svaluent
vrai. Si lune delles est fausse, lexpression globale est fausse. Le langage C exploite ce
fonctionnement et, avec une expression de la forme if (A && B) { ... }, commence
par valuer A. Si cette expression est fausse, il ne tente mme pas dvaluer B, puisque le
rsultat de lvaluation globale est dj connu (faux, puisque A a t value faux).
Quel est donc le lien avec bash ? Si ltat de sortie de la premire commande (celle gauche de &&) est diffrent de zro (elle a chou), alors la deuxime expression nest pas
value. Autrement dit, lautre commande nest pas excute.
Si vous voulez grer les erreurs, mais sans multiplier les instructions if, indiquez bash
de quitter le script ds quil rencontre une erreur (un tat de sortie diffrent de zro)
dans une commande ( lexception des boucles while et des instructions if dans lesquelles il utilise dj ltat de sortie). Pour cela, activez loption -e.
set -e
cd monTmp
rm *

Lorsque loption -e est active, le shell interrompt lexcution du script ds quune commande choue. Par exemple, si la commande cd choue, le script se termine et ne passe
jamais par la commande rm *. Nous dconseillons cette solution avec un shell interactif,
car, si le shell se termine, sa fentre disparat galement.

Voir aussi

la recette 4.8, Afficher des messages en cas derreur, page 80, pour une explication de
la syntaxe ||, qui est similaire, en un sens, mais galement assez diffrente de &&.

4.7. Lancer de longues tches sans surveillance


Problme
Vous dmarrez une tche en arrire-plan, puis quittez le shell et partez prendre un caf.
Lorsque vous revenez, la tche ne sexcute plus, mais elle nest pas termine. En ralit,
la tche na gure progress et semble stre arrte ds que vous avez quitt le shell.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

80

Chapitre 4 Excuter des commandes

Solution
Si vous lancez une tche en arrire-plan et voulez quitter le shell avant la fin de la tche,
vous devez alors dmarrer la tche avec nohup :
$ nohup long &
nohup: ajout la sortie de `nohup.out'
$

Discussion
Lorsque vous placez la tche en arrire-plan (avec &), elle reste un processus enfant du
shell bash. Si vous quittez une instance du shell, bash envoie un signal darrt (hang-up)
tous ses processus enfants. Cest pour cela que lexcution de votre tche na pas dur
trs longtemps. Ds que vous avez quitt bash, il a tu votre tche darrire-plan.
La commande nohup configure simplement les processus enfants de manire ce quils
ignorent les signaux darrt. Vous pouvez toujours stopper une tche avec la commande
kill, car elle envoie un signal SIGTERM et non un signal SIGHUP. Mais avec nohup, bash ne
tuera pas incidemment votre tche.
nohup affiche un message prcisant quelle ajoute votre sortie un fichier. En ralit,
elle essaie juste dtre utile. Puisque vous allez certainement quitter le shell aprs avoir
lanc une commande nohup, la sortie de la commande sera perdue (la session bash dans
la fentre de terminal ne sera plus active). Par consquent, o la tche peut-elle envoyer
sa sortie ? Plus important encore, si elle est envoye vers une destination inexistante,
elle peut provoquer une erreur. nohup redirige donc la sortie votre place et lajoute au
fichier nohup.out dans le rpertoire de travail. Si vous redirigez explicitement la sortie
sur la ligne de commande, nohup est suffisamment intelligente pour le dtecter et ne
pas utiliser nohup.out.

Voir aussi

le chapitre 2, Sortie standard, page 31, pour la redirection de la sortie, car cela vous
sera certainement utile pour une tche en arrire-plan ;

la recette 10.1, Convertir un script en dmon, page 207 ;

la recette 17.4, Restaurer des sessions dconnectes avec screen, page 433.

4.8. Afficher des messages en cas derreur


Problme
Vous souhaitez que votre script shell soit plus bavard lorsquil rencontre des erreurs.
Vous voulez obtenir des messages derreur lorsque des commandes ne fonctionnent pas,
mais les instructions if ont tendance masquer le droulement des commandes.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

4.9. Excuter des commandes places dans une variable

81

Solution
Parmi les programmeurs shell, lidiome classique consiste utiliser || avec les commandes afin de gnrer des messages de dbogage ou derreur. En voici un exemple :
cmd || printf "%b" "chec de cmd. vous de jouer...\n"

Discussion
Similaire && dans les conditions dvaluation de la seconde expression, || indique au
shell de ne pas se proccuper de lvaluation de la seconde expression si la premire est
vraie (en cas de succs). Comme pour &&, la syntaxe de || est issue de la logique et du
langage C, dans lequel le rsultat global est connu (vrai) si la premire expression de A
OU B svalue vrai ; il est donc inutile dvaluer la seconde expression. Dans bash, si la
premire expression retourne 0 (russit), lexcution se poursuit. Ce nest que si la premire expression retourne une valeur diffrente de zro que la deuxime partie est value et donc excute.
Attention, ne tombez pas dans le pige suivant :
cmd || printf "%b" "CHEC.\n" ; exit 1

Linstruction exit est excute dans tous les cas ! Le OU concerne uniquement les deux
commandes qui lentourent. Si vous voulez quexit ne soit excute que dans une situation derreur, vous devez la regrouper avec printf. Par exemple :
cmd || { printf "%b" "CHEC.\n" ; exit 1 ; }

Les singularits de la syntaxe de bash imposent la prsence du point-virgule aprs la dernire commande, juste avant }. Par ailleurs, cette accolade fermante doit tre spare du
texte environnant par une espace.

Voir aussi

la recette 2.14, Enregistrer ou runir la sortie de plusieurs commandes, page 44 ;

la recette 4.6, Utiliser moins dinstructions if, page 78, pour une explicaiton de la syntaxe de &&.

4.9. Excuter des commandes places dans une


variable
Problme
Vous souhaitez que votre script excute des commandes diffrentes selon certaines conditions. Comment pouvez-vous modifier la liste des commandes excutes ?

Solution
Il existe de nombreuses solutions ce problme ; cest tout lobjectif des scripts. Dans les
chapitres venir, nous tudierons diffrentes logiques de programmation permettant
de rsoudre ce problme, comme les instructions if/then/else ou case. Voici une ap[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

82

Chapitre 4 Excuter des commandes

proche assez diffrente qui souligne les possibilits de bash. Nous pouvons nous servir
du contenu dune variable (voir le chapitre 5), non seulement pour les paramtres, mais
galement pour la commande elle-mme :
FN=/tmp/x.x
PROG=echo
$PROG $FN
PROG=cat
$PROG $FN

Discussion
Le nom du programme est plac dans une variable (ici $PROG), laquelle nous faisons
ensuite rfrence l o le nom dune commande est attendu. Le contenu de la variable
($PROG) est alors interprt comme la commande excuter. Le shell bash analyse la ligne de commande, remplace les variables par leur valeur, puis prend le rsultat de toutes les substitutions et le traite comme sil avait t saisi directement sur la ligne de
commande.
Attention aux noms des variables que vous utilisez. Certains programmes, comme InfoZip, utilisent leurs propres variables denvironnement, comme $ZIP et $UNZIP, pour le passage de paramtres. Si vous
utilisez une instruction comme ZIP='/usr/bin/zip', vous risquez de
passer plusieurs jours essayer de comprendre pourquoi cela fonctionne depuis la ligne de commande, mais pas dans votre script. Vous
pouvez nous croire sur parole, nous parlons par exprience.

Voir aussi

le chapitre 11, Dates et heures, page 223 ;

la recette 14.3, Dfinir une variable $PATH sre, page 294 ;

la recette 16.19, Crer des fichiers dinitialisation autonomes et portables, page 414 ;

la recette 16.20, Commencer une configuration personnalise, page 416 ;

lannexe C, Analyse de la ligne de commande, page 569, pour une description des diffrentes substitutions effectues sur la ligne de commande ; vous lisez les autres
chapitres avant dexaminer ce sujet.

4.10. Excuter tous les scripts dun rpertoire


Problme
Vous souhaitez excuter un ensemble de scripts, mais la liste volue en permanence.
Vous ajoutez continuellement de nouveaux scripts, mais vous ne voulez pas grer une
liste.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

4.10. Excuter tous les scripts dun rpertoire

83

Solution
Placez les scripts excuter dans un rpertoire, puis demandez bash dinvoquer tout
ce quil y trouve. Au lieu de grer une liste, vous pouvez simplement adapter le contenu
de ce rpertoire. Voici un script qui excute tous les programmes qui se trouvent dans
un rpertoire :
for SCRIPT in /chemins/vers/les/scripts/*
do
if [ -f $SCRIPT -a -x $SCRIPT ]
then
$SCRIPT
fi
done

Discussion
Nous reviendrons en dtail sur la boucle for et linstruction if au chapitre 6. La variable $SCRIPT va successivement contenir le nom de chaque fichier qui correspond au motif *, cest--dire tout ce qui se trouve dans le rpertoire de travail (except les fichiers
invisibles qui commencent par un point). Si le contenu de la variable correspond un
fichier (le test -f), dont les autorisations dexcution sont actives (le test -x), le shell tente de lexcuter.
Dans cet exemple simple, nous noffrons pas la possibilit de passer des arguments aux
scripts excuts. Il sera peut-tre adapt vos besoins personnels, mais il ne peut tre
qualifi de robuste. Certains pourraient mme le considrer comme dangereux. Cependant, nous esprons que vous avez compris lide sous-jacente : les scripts peuvent bnficier de certaines structures dcriture, comme les langages de programmation.

Voir aussi

le chapitre 6, Logique et arithmtique, page 113, pour plus dinformations sur les
boucles for et les instructions if.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5
Variables du shell

La programmation avec le shell bash ressemble aux autres formes de programmation,


notamment par lexistence de variables. Il sagit demplacements permettant de stocker
des chanes et des nombres, qui peuvent tre modifis, compars et passs entre les diffrentes parties du programme. bash dispose doprateurs particuliers qui savrent trs
utiles lors des rfrences aux variables. bash fournit galement des variables internes,
qui apportent des informations indispensables sur les autres variables dun script. Ce
chapitre prsente les variables de bash et certains mcanismes spcifiques employs dans
les rfrences aux variables. Il explique galement comment vous en servir dans vos
scripts.
Dans un script bash, les variables sont gnralement crites en majuscules, bien que rien
ne vous y oblige ; il sagit dune pratique courante. Vous navez pas besoin de les dclarer, juste de les utiliser lorsque vous le souhaitez. Elles sont toutes de type chane de caractres, mme si certaines oprations de bash peuvent traiter leur contenu comme des
nombres. Voici un exemple dutilisation :
# Script trs simple qui utilise des variables du shell
# (nanmoins, il est bien comment).
MAVAR="valeur"
echo $MAVAR
# Une deuxime variable, mais sans les guillemets.
MA_2E=uneAutre
echo $MA_2E
# Les guillemets sont indispensables dans le cas suivant :
MONAUTRE="autre contenu pour echo"
echo $MONAUTRE

La syntaxe des variables de bash prsente deux aspects importants qui ne sont peut-tre
pas intuitivement vidents pour des variables de shell. Tout dabord, la syntaxe daffectation nom=valeur est suffisamment simple, mais il ne peut y avoir despace autour du
signe gal.
Pourquoi est-ce ainsi ? Le rle fondamental du shell est de lancer des programmes. Vous
nommez le programme sur la ligne de commande et le shell lexcute. Tous les mots qui
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

86

Chapitre 5 Variables du shell

se trouvent aprs ce nom sur la ligne de commande constituent les arguments du programme. Prenons, par exemple, la commande suivante :
$ ls nomFichier

ls est le nom de la commande et nomFichier est son premier et seul argument.


Quel est le rapport ? Examinons laffectation dune variable dans bash en autorisant les
espaces autour du signe gal :
MAVAR = valeur

Vous pouvez facilement imaginer que le shell aura quelques difficults diffrencier le
nom dune commande invoquer (comme lexemple de ls) et laffectation dune variable. Cest notamment le cas pour les commandes qui peuvent utiliser des symboles =
dans leurs arguments (par exemple test). Par consquent, pour faire dans la simplicit,
le shell refuse les espaces autour du signe gal dune affectation. Dans le cas contraire, il
interprte chaque lment comme des mots spars. Ce choix a un effet secondaire.
Vous ne pouvez pas placer de signe gal dans le nom dun fichier, en particulier celui
dun script shell (en ralit cest possible, mais fortement dconseill).
Le deuxime aspect important de la syntaxe des variables du shell rside dans lutilisation du symbole dollar ($) pour les rfrences aux variables. Il nest pas ajout au nom
de la variable lors de laffectation, mais indispensable pour obtenir sa valeur. Les variables places dans une expression $(( ... )) font exception cette rgle. Du point de vue
du compilateur, cette diffrence dans la syntaxe daffectation et dobtention de la valeur
dune variable a un rapport avec la valeur-L et la valeur-R de la variable pour le ct
gauche (L) et droit (D) de loprateur daffectation.
Une fois encore, la raison de cette distinction rside dans la simplicit. Prenons le cas
suivant :
MAVAR=valeur
echo MAVAR vaut prsent MAVAR

Comme vous pouvez le constater, il nest pas vident de diffrencier la chane littrale
"MAVAR" et la valeur de la variable $MAVAR. Vous pourriez penser utiliser des guillemets, mais si toutes les chanes littrales devaient tre places entre guillemets, la lisibilit et la simplicit dutilisation en souffriraient normment. En effet, tous les noms
autres que ceux dune variable devraient tre placs entre guillemets, ce qui inclut les
commandes ! Avez-vous vraiment envie de saisir la ligne suivante ?
$ "ls" "-l" "/usr/bin/xmms"

Cela dit, elle fonctionne parfaitement. Au lieu de tout placer entre des guillemets, il est
plus simple de faire rfrence aux variables en utilisant la syntaxe de la valeur-R. Ajoutez un symbole dollar devant le nom dune variable pour obtenir sa valeur :
MAVAR=valeur
echo MAVAR vaut prsent $MAVAR

Puisque bash ne manipule que des chanes de caractres, nous avons besoin du symbole
dollar pour reprsenter une rfrence une variable.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.1. Documenter un script

87

5.1. Documenter un script


Problme
Avant daller plus loin sur les scripts shell ou les variables, vous devez savoir comment
documenter vos scripts. En effet, il ny a rien de plus important que de pouvoir comprendre le contenu du script, surtout plusieurs mois aprs lavoir crit.

Solution
Documentez votre script en ajoutant des commentaires. Le caractre # reprsente le dbut dun commentaire. Tous les caractres qui viennent ensuite sur la ligne sont ignors
par le shell.
#
# Voici un commentaire.
#
# Utilisez les commentaires le plus souvent possible.
# Les commentaires sont vos amis.

Discussion
Certaines personnes considrent que le shell, les expressions rgulires et dautres lments des scripts shell ont une syntaxe en criture uniquement. Elles veulent simplement
dire quil est pratiquement impossible de comprendre les complexits de nombreux
scripts shell.
La meilleure dfense contre ce pige consiste employer les commentaires (vous pouvez aussi utiliser des noms de variables significatifs). Avant toute syntaxe trange ou expression complique, il est fortement conseill dajouter un commentaire :
# Remplacer le point-virgule par une espace.
NOUVEAU_PATH=${PATH/;/ }
#
# changer le texte qui se trouve des deux cts dun point-virgule.
sed -e 's/^\(.*\);\(.*\)$/\2;\1/' < $FICHIER

Dans un shell interactif, les commentaires peuvent mme tre saisis linvite de commande. Il est possible de dsactiver cette fonction, mais elle est active par dfaut. Dans
certains cas, il peut tre utile dajouter des commentaires en mode interactif.

Voir aussi

la section Options de shopt, page 517, pour lactivation et la dsactivation des commentaires.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

88

Chapitre 5 Variables du shell

5.2. Incorporer la documentation dans les


scripts
Problme
Vous souhaitez disposer dun moyen simple pour fournir une documentation mise en
forme lutilisateur final de votre script (par exemple, des pages de manuel ou des pages
HTML). Vous voulez conserver le code et la documentation dans le mme fichier afin
de simplifier les mises jour et la distribution.

Solution
Incorporez la documentation dans le script en utilisant la commande ne fait rien
(les deux-points) et un document en ligne :
#!/usr/bin/env bash
# bash Le livre de recettes : documentation_incorporee
echo 'Le code du script shell vient ici'
# Utilisez une commande "ne fait rien" (:) et un document en ligne
# pour incorporer la documentation.
: <<'FIN_DE_DOC'
Incorporez ici la documentation au format POD (Plan Old Documentation)
de Perl ou en texte brut.
Une documentation jour est prfrable aucune documentation.
Exemple de documentation au format POD de Perl adapt des exemples
CODE/ch07/Ch07.001_Best_Ex7.1 et 7.2 du livre De l'art de programmer
en Perl (ditions O'Reilly).
=head1 NAME
MON~PROGRAMME--Une ligne de description
=head1 SYNOPSIS
MON~PROGRAMME [OPTIONS] <fichier>
=head1 OPTIONS
-h = Cette aide.
-v = tre plus bavard.
-V = Afficher la version, le copyright et la licence.
=head1 DESCRIPTION

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.2. Incorporer la documentation dans les scripts

89

Une description complte de l'application et de ses fonctionnalits.


Peut comporter des sous-sections (cd =head2, =head3, etc.)

[...]

=head1 LICENCE AND COPYRIGHT


=cut
FIN_DE_DOC

Ensuite, pour extraire et utiliser la documentation POD, servez-vous des commandes


suivantes :
# Pour un affichage lcran, avec pagination automatique.
$ perldoc monScript

# Uniquement les sections "utilisation".


$ pod2usage monScript

# Crer une version HTML.


$ pod2html monScript > monScript.html

# Crer une page de manuel.


$ pod2man monScript > monScript.1

Discussion
Toute documentation en texte brut ou balis peut tre utilise de cette manire, quelle
soit mlange au code ou, mieux encore, place la fin de script. Lorsque bash est install sur un systme, il est fort probable que Perl lest galement. Par consquent, le format POD (Plain Old Documentation) est un bon choix. Perl est gnralement fourni avec
des programmes pod2* qui convertissent POD en fichiers HTML, LaTeX, de page de manuel, texte et utilisation.
De lart de programmer en Perl de Damian Conway (ditions OReilly) propose un excellent module de bibliothque et des modles de documentation qui peuvent tre facilement convertis dans tout format de documentation, y compris le texte brut. Consultez
les exemples CODE/ch07/Ch07.001_Best_Ex7.1 et 7.2 dans larchive disponible ladresse
http://www.oreilly.fr/archives/3698Exemples.tar.gz.
Si lintgralit de la documentation est incorpore tout la fin de script, vous pouvez
galement ajouter une instruction exit 0 juste avant le dbut de la documentation.
Cela permet ainsi de quitter le script sans obliger le shell analyser chacune des lignes
la recherche de la fin du document en ligne. Si vous mlangez code et documentation
au cur du script, vitez dutiliser cette instruction.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

90

Chapitre 5 Variables du shell

Voir aussi

http://www.oreilly.fr/archives/3698Exemples.tar.gz ;

Embedding manpages in Shell Scripts with kshdoc http://www.unixlabplus.


com/unix-prog/kshdoc/kshdoc.html

5.3. Amliorer la lisibilit des scripts


Problme
Vous souhaitez rendre votre script aussi lisible que possible, afin den faciliter la comprhension et la maintenance ultrieure.

Solution

documentez votre script comme lexpliquent les recettes 5.1, page 87, et 5.2, page
88 ;

indentez et utilisez lespacement vertical avec soin ;

donnez des noms significatifs aux variables ;

utilisez des fonctions et donnez-leur des noms significatifs ;

coupez les lignes des emplacements judicieux, moins de 76 caractres (environ) ;

placez les lments les plus importants gauche.

Discussion
La documentation doit expliquer les objectifs et non les dtails vidents du code. Si vous
respectez les autres points, votre code devrait tre clair. Ajoutez des rappels, fournissez
des donnes dexemple ou des intituls et notez tous les dtails qui se trouvent dans votre tte au moment o vous crivez le code. Si certaines parties du code lui-mme sont
subtiles ou obscures, documentez-les.
Nous conseillons dutiliser quatre espaces par niveau dindentation, sans tabulation et
surtout sans mlanger espaces et tabulations. Les raisons de cette recommandation sont
nombreuses, mme sil sagit souvent de prfrences personnelles ou professionnelles.
En effet, quatre espaces reprsentent toujours quatre espaces, quelle que soit la configuration de votre diteur (except avec des polices proportionnelles) ou de votre imprimante. Quatre espaces sont suffisamment visibles lorsque vous parcourez le script et
restent suffisamment courtes pour autoriser plusieurs niveaux dindentation sans que
les lignes soient colles sur la droite de lcran ou de la page imprime. Nous vous suggrons galement dindenter les instructions occupant plusieurs lignes avec deux espaces supplmentaires, ou plus, pour que le code soit plus clair.
Utilisez les espaces verticaux, avec ou sans sparateur, pour crer des blocs de code connexe. Faites-le galement pour les fonctions.
Donnez des noms significatifs aux variables et aux fonctions. Le seul endroit o des
noms comme $i ou $x peuvent tre accepts est dans une boucle for. Vous pourriez
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.3. Amliorer la lisibilit des scripts

91

penser que des noms courts et cods permettent de gagner du temps sur le moment,
mais nous pouvons vous assurer que la perte de temps sera dix cent fois suprieure
lorsque vous devrez corriger ou modifier le script.
Limitez les lignes environ 76 caractres. Nous savons bien que la plupart des crans
peuvent faire mieux que cela. Mais, le papier et les terminaux offrant 80 caractres sont
encore trs rpandus et vous pourriez avoir besoin dun peu despace droite du code.
Il est assez pnible de devoir constamment utiliser la barre de dfilement vers la droite
ou que les instructions passent automatiquement la ligne sur lcran ou le papier.
Malheureusement, il existe des exceptions ces rgles. Lorsque vous crivez des lignes
qui doivent tre passes dautres programmes, peut-tre via SSH (Secure Shell), ainsi
que dans dautres situations particulires, leur coupure risque de poser plus de problmes que den rsoudre. Cependant, dans la plupart des cas, elle est prfrable.
Lorsque vous coupez des lignes, essayez de placer les lments les plus importants gauche. En effet, nous lisons le code de gauche droite et la nuisance due la coupure de
la ligne est alors moindre. Il est galement ainsi plus facile de parcourir le ct gauche
du code sur plusieurs lignes. Parmi les exemples suivants, lequel trouvez-vous le plus facile lire ?
# Bon.
[ $resultats ] \
&& echo "Nous avons un bon rsultat dans $resultats" \
|| echo 'Le rsultat est vide, il y a un problme'

# galement bon.
[ $resultats ] && echo "Nous avons un bon rsultat dans $resultats" \
|| echo 'Le rsultat est vide, il y a un problme'

# OK, mais pas idal.


[ $resultats ] && echo "Nous avons un bon rsultat dans $resultats" \
|| echo 'Le rsultat est vide, il y a un problme'

# Mauvais.
[ $resultats ] && echo "Nous avons un bon rsultat dans $resultats" || echo
'Le rsultat est vide, il y a un problme'

# Mauvais.
[ $resultats ] && \
echo "Nous avons un bon rsultat dans $resultats" || \
echo 'Le rsultat est vide, il y a un problme'

Voir aussi

la recette 5.1, Documenter un script, page 87 .

la recette 5.2, Incorporer la documentation dans les scripts, page 88.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

92

Chapitre 5 Variables du shell

5.4. Sparer les noms de variables du texte


environnant
Problme
Vous souhaitez afficher une variable au ct dun autre texte. Vous utilisez le symbole
dollar dans la rfrence la variable. Cependant, comment pouvez-vous distinguer la
fin du nom de la variable et le texte qui vient ensuite ? Par exemple, supposons que vous
utilisiez une variable en tant que partie du nom dun fichier :
for NF in 1 2 3 4 5
do
unScript /tmp/rap$NFport.txt
done

Comment le shell va-t-il interprter cela ? Il suppose que le nom de la variable commence au symbole $ et se termine au symbole de ponctuation. Autrement dit, il considre
que la variable se nomme $NFport la place de $NF.

Solution
Utilisez la syntaxe complte dune rfrence de variable, qui inclut non seulement le
symbole dollar, mais galement des accolades autour du nom :
unScript /tmp/rap${NF}port.txt

Discussion
Puisque les noms des variables du shell sont uniquement constitus de caractres alphanumriques, les accolades ne sont pas toujours ncessaires. Une espace ou un signe de
ponctuation (except le soulign) indique trs clairement la fin du nom dune variable.
Mais, en cas de doute, utilisez les accolades.

Voir aussi

la recette 1.6, Protger la ligne de commande, page 12.

5.5. Exporter des variables


Problme
Vous avez dfini une variable dans un script, mais, lorsque vous appelez un autre script,
elle nest pas connue.

Solution
Exportez les variables que vous souhaitez passer dautres scripts :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.5. Exporter des variables

93

export MAVAR
export NOM=valeur

Discussion
Il est parfois prfrable quun script ne connaisse pas les variables dun autre. Si vous
appelez un script shell depuis lintrieur dune boucle for dun premier script, vous ne
voulez pas que le second perturbe les itrations de votre boucle for.
En revanche, vous pourriez vouloir passer des informations des scripts. Dans ce cas,
exportez la variable afin que sa valeur soit connue des autres programmes invoqus par
votre script.
Pour obtenir la liste de toutes les variables exportes, et leur valeur, excutez la commande interne env (ou export -p). Elles sont toutes accessibles votre script lors de son
excution. Pour la plupart, elles ont t dfinies par les scripts de dmarrage de bash
(voir le chapitre 16 sur la configuration et la personnalisation de bash).
Linstruction dexportation peut simplement nommer la variable exporter. Mme si
cette instruction peut tre place juste avant lendroit o vous avez besoin dexporter la
valeur, les dveloppeurs regroupent souvent ces instructions avec les dclarations de variables au dbut du script. Vous pouvez galement effectuer lexportation lors laffectation de la variable, mais cela ne fonctionne pas dans les anciennes versions du shell.
Une fois la variable exporte, vous pouvez modifier sa valeur sans lexporter nouveau.
Vous rencontrerez donc parfois des instructions similaires aux suivantes :
export NOMFICHIER
export TAILLE
export MAX
...
MAX=2048
TAILLE=64
NOMFICHIER=/tmp/toto

ou bien :
export NOMFICHIER=/tmp/toto
export TAILLE=64
export MAX=2048
...
NOMFICHIER=/tmp/toto2
...
NOMFICHIER=/tmp/toujours_exporte

Attention : les variables sont exportes par valeur. Si vous modifiez la valeur dans le
script appel, sa valeur lors du retour dans le script appelant na pas chang.
Se pose donc la question comment renvoyer au script appelant une valeur modifie
dans le script appel ? . La rponse est claire : cest impossible.
Malheureusement, il nexiste pas dautres rponses. Vous devez concevoir vos scripts de
manire ce quils naient pas besoin de cette fonctionnalit. Quels mcanismes emploient donc les dveloppeurs pour sadapter cette contrainte ?

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

94

Chapitre 5 Variables du shell

Une solution consiste envoyer la valeur modifie sur la sortie du script appel et la
lire dans le script appelant. Par exemple, supposons quun script exporte la variable
$VAL et appelle ensuite un autre script qui la modifie. Pour obtenir la nouvelle valeur,
le script invoqu doit lafficher sur la sortie standard et le script invoquant doit la lire et
laffecter $VAL (voir la recette 10.5, page 213) :
VAL=$(unAutreScript)

Vous pouvez mme modifier plusieurs valeurs et les afficher tour tour sur la sortie
standard. Le programme appelant utilise ensuite une instruction read pour rcuprer
chaque ligne de la sortie et les placer dans les variables adquates. Cependant, le script
appel ne doit rien afficher dautre sur la sortie standard (tout au moins avant ou parmi
les variables) et cela cre une dpendance trs forte entre les scripts (peu intressant
quant leur maintenance).

Voir aussi

help export ;

le chapitre 16, Configurer bash, page 367, pour plus dinformations sur la configuration et la personnalistion de bash ;

la recette 5.6, Afficher les valeurs de toutes les variables, page 94 ;

la recette 10.5, Utiliser des fonctions : paramtres et valeur de retour, page 213 ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490.

5.6. Afficher les valeurs de toutes les variables


Problme
Vous souhaitez voir la liste de toutes les variables exportes et leur valeur. Devez-vous
afficher chacune delles avec echo ? Comment savoir quelles sont exportes ?

Solution
Utilisez la commande set pour obtenir la valeur de toutes les variables et les dfinitions
de fonctions du shell courant.
Utilisez la commande env (ou export -p) pour obtenir uniquement les variables qui ont
t exportes et qui sont disponibles dans les sous-shells.

Discussion
La commande set, invoque sans autre argument, affiche sur la sortie standard la liste
de toutes les variables du shell actuellement dfinies ainsi que leur valeur, dans le format nom=valeur. La commande env est similaire. Lune ou lautre produit une liste assez
longue de variables, dont certaines vous seront inconnues. Elles ont t cres pendant
le processus de dmarrage du shell.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.7. Utiliser des paramtres dans un script

95

La liste gnre par env est un sous-ensemble de celle cre set, puisque toutes les variables ne sont pas exportes.
Si vous ntes intress que par quelques variables ou valeurs prcises, utilisez un tube
vers une commande grep. Par exemple :
$ set | grep MA

Dans ce cas, seules les variables dont le nom ou la valeur contient les deux caractres MA
sont prsentes.

Voir aussi

help set ;

help export ;

man env ;

le chapitre 16 pour plus dinformations sur la configuration et la personnalistion


de bash ;

lannexe A pour la liste de toutes les variables internes au shell.

5.7. Utiliser des paramtres dans un script


Problme
Vous souhaitez que les utilisateurs puissent invoquer votre script avec un paramtre.
Vous pourriez leur demander de dfinir une variable du shell, mais cela ne se fait pas.
Vous avez galement besoin de passer des donnes un autre script. Vous pourriez accorder les deux scripts quant aux variables denvironnement utilises, mais cela cre une
trop grande dpendance entre eux.

Solution
Utilisez les paramtres de la ligne de commande. Tous les mots placs sur la ligne de
commande dun script shell lui sont accessibles au travers de variables numrotes :
# Script shell simple.
echo $1

Le script affiche le premier paramtre fourni sur la ligne de commande au moment de


son invocation. Le voici en action :
$ cat tres_simple.sh
# Script shell simple.
echo ${1}
$ ./tres_simple.sh vous voyez ce que je veux dire
vous
$ ./tres_simple.sh encore une fois
encore
$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

96

Chapitre 5 Variables du shell

Discussion
Les autres paramtres sont disponibles dans les variables ${2}, ${3}, ${4}, ${5}, etc. Les
accolades sont inutiles avec les nombres dun chiffre, except pour sparer les noms du
texte environnant. En gnral, les scripts nattendent que quelques paramtres, mais, si
vous arrivez ${10}, vous devez utiliser les accolades ou le shell pensera quil sagit de
la variable ${1} immdiatement suivie de la chane littrale 0 :
$ cat delicat.sh
echo $1 $10 ${10}
$ ./delicat.sh I II III IV V VI VII VIII IX X XI
I I0 X
$

La valeur du dixime argument est X, mais si vous crivez $10 dans votre script, le shell
affiche alors $1, le premier paramtre, suivi immdiatement dun zro, le caractre littral plac ct de $1 dans linstruction echo.

Voir aussi

la recette 5.4, Sparer les noms de variables du texte environnant, page 92.

5.8. Parcourir les arguments dun script


Problme
Vous souhaitez effectuer certaines oprations sur la liste des arguments. Vous savez crire le script de manire traiter un argument en utilisant $1, mais comment prendre en
charge un nombre quelconque de paramtres ? Vous souhaitez tre en mesure dinvoquer votre script de la manire suivante :
toutTraiter *.txt

Le shell va construire une liste de noms de fichiers qui correspondent aux motifs *.txt
(pour les noms qui se terminent par .txt).

Solution
Utilisez la variable spciale du shell $* pour faire rfrence tous les arguments dans
une boucle for :
# bash Le livre de recettes : chmod_tous.1
#
# Modifier les autorisations d'un ensemble de fichiers.
#
for NF in $*
do
echo modification de $NF
chmod 0750 $NF
done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.9. Accepter les paramtres contenant des espaces

97

Discussion
Le choix de la variable $NF vous revient. Vous pouvez utiliser nimporte quel nom de
variable. $* fait rfrence tous les arguments fournis sur la ligne de commande. Par
exemple, si lutilisateur saisit la ligne suivante :
$ ./chmod_tous.1 abc.txt unAutre.txt toutesMesNotes.txt

le script est invoqu avec la variable $1 gale abc.txt, la variable $2 gale unAutre.txt
et la variable $3 gale toutesMesNotes.txt, mais $* contient la liste complte. Autrement
dit, dans linstruction for, la variable $* est remplace par la liste, ce qui quivaut crire le code suivant :
for NF in abc.txt unAutre.txt toutesMesNotes.txt
do
echo modification de $NF
chmod 0750 $NF
done

La boucle for prend une valeur de la liste la fois, laffecte la variable $NF et poursuit
lexcution des instructions places entre do et done. La boucle est ensuite recommence
pour chacune des autres valeurs.
Mais ce nest pas encore fini ! Ce script fonctionne uniquement avec les fichiers dont les
noms ne contiennent pas despace. Consultez les deux recettes suivantes pour savoir
comment lamliorer.

Voir aussi

help for ;

la recette 6.12, Boucler avec un compteur, page 135.

5.9. Accepter les paramtres contenant des


espaces
Problme
Vous avez crit un script qui attend un nom de fichier en paramtre et il semblait fonctionner parfaitement jusqu ce que lun des noms de fichiers contienne une espace.

Solution
Vous devez placer entre guillemets les paramtres qui pourraient contenir des noms de
fichiers. Lorsque vous faites rfrence une variable, placez la rfrence entre des guillemets (").

Discussion
Merci beaucoup, Apple ! En voulant tre plus agrables lutilisateur, ils ont rpandu
lutilisation des espaces dans les noms de fichiers. Il est ainsi devenu possible de donner

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

98

Chapitre 5 Variables du shell

des noms comme Mon rapport et Nos chiffres de vente la place des moins agrables
MonRapport et Nos_chiffres_de_vente. Si lutilisateur en a t satisfait, la vie du shell sen
est trouve complique, car lespace est pour lui un sparateur de mots. Les noms de fichiers constituaient prcdemment un seul mot, mais ce nest plus le cas et nous devons
en tenir compte.
L o un script shell utilisait simplement ls -l $1, il est dsormais prfrable dcrire
ls -l "$1", avec des guillemets autour du paramtre. Sans cela, si le paramtre inclut
une espace, il sera trait comme deux mots spars et seule une partie du nom se trouvera dans $1. Examinons ce dysfonctionnement :
$ cat simple.sh
# Script shell simple.
ls -l ${1}
$
$ ./simple.sh Oh quel gachis
ls: Oh: Aucun fichier ou rpertoire de ce type
$

Lors de linvocation du script, nous navons pas plac le nom de fichier entre guillemets.
bash voit donc trois arguments et place le premier (Oh) dans $1. La commande ls sexcute donc avec Oh comme seul argument et ne trouve pas ce fichier.
Invoquons prsent le script en plaant des guillemets autour du nom de fichier :
$ ./simple.sh "Oh quel gachis"
ls: Oh: Aucun fichier ou rpertoire de ce type
ls: quel: Aucun fichier ou rpertoire de ce type
ls: gachis: Aucun fichier ou rpertoire de ce type
$

Ce nest pas encore le rsultat attendu. bash a pris le nom de fichier constitu de trois
mots et la plac dans la variable $1 qui se trouve sur la ligne de la commande ls dans
notre script. Mais, puisque nous navons pas plac la rfrence la variable entre des
guillemets, ls considre chaque mot comme un argument distinct, cest--dire des noms
de fichiers spars. Elle ne trouve aucun deux.
Essayons une version du script qui entoure la rfrence par des guillemets :
$ cat entreGuillemets.sh
# Notez les guillemets.
ls -l "${1}"
$
$ ./entreGuillemets.sh "Oh quel gachis"
-rw-r--r-- 1 jp jp 0 2007-06-20 14:12 Oh quel gachis
$

Puisque la rfrence "{$1}" est place entre guillemets, elle est traite comme un seul
mot (un seul nom de fichier) et la commande ls reoit alors un seul argument, cest-dire le nom du fichier, et peut effectuer son travail.

Voir aussi

le chapitre 19, Bourdes du dbutant, page 485, pour les erreurs classiques ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.10. Accepter des listes de paramtres contenant des espaces

99

la recette 1.6, Protger la ligne de commande, page 12 ;

lannexe A, Listes de rfrence, page 505 pour plus dinformations sur le traitement
de la ligne de commande.

5.10. Accepter des listes de paramtres


contenant des espaces
Problme
Comme la conseill la recette prcdente, vous avez plac des guillemets autour de votre variable. Cependant, vous obtenez toujours des erreurs. Votre script est similaire
celui de la recette 5.8, page 96, mais il choue lorsque le nom dun fichier contient une
espace :
#
for NF in $*
do
chmod 0750 "$NF"
done

Solution
Le problme vient de la variable $* employe dans la boucle for. Dans ce cas, nous devons utiliser une autre variable du shell, $@. Lorsquelle est place entre guillemets, chaque argument de la liste rsultante est entour de guillemets. Le script peut donc tre
crit de la manire suivante :
#!/usr/bin/env bash
# bash Le livre de recettes : chmod_tous.2
#
# Modifier les autorisations d'un ensemble de fichiers avec les
# guillemets adapts pour le cas o des noms de fichiers incluent
# des espaces.
#
for NF in "$@"
do
chmod 0750 "$NF"
done

Discussion
La variable $* contient la liste des arguments fournis au script shell. Prenons par exemple linvocation suivante du script :
$ monScript voici les arguments

$* fait alors rfrence aux trois arguments voici les arguments. Employez cette variable dans une boucle for :
for NF in $*
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

100

Chapitre 5 Variables du shell

Au premier tour de boucle, le premier mot (voici) est affect $NF. Au deuxime tour,
le deuxime mot (les) est affect $NF, etc.
Les arguments peuvent tre des noms de fichiers placs sur la ligne de commande grce
une correspondance de motifs. Par exemple :
$ monScript *.mp3

Le shell slectionne alors tous les fichiers du rpertoire courant dont les noms se terminent par les quatre caractres .mp3 et les passe au script. Prenons un exemple avec trois
fichiers MP3 :
voix.mp3
musique planante.mp3
hit.mp3

Le nom du deuxime fichier contient une espace entre musique et planante. Linvocation suivante :
$ monScript *.mp3

donne en ralit ceci :


$ monScript voix.mp3 musique planante.mp3 hit.mp3

Si le script contient la ligne :


for NF in $*

elle est remplace par :


for NF in voix.mp3 musique planante.mp3 hit.mp3

La liste contient donc quatre mots et non trois. Le huitime caractre du nom du
deuxime fichier est une espace (musique planante.mp3), or les espaces sont considres comme des sparateurs de mots par le shell (musique et planante.mp3). $NF aura
donc la valeur musique lors de la deuxime itration de la boucle for. la troisime itration, $NF prendra la valeur planante.mp3, qui ne correspond pas non plus au nom de
votre fichier. Vous obtiendrez alors des messages derreur concernant des fichiers non
trouvs.
Il semblerait logique dessayer de placer $* entre guillemets :
for NF in "$*"

Mais la ligne devient alors :


for NF in "voix.mp3 musique planante.mp3 hit.mp3"

La variable $NF contient donc une seule valeur qui correspond lintgralit de la liste.
Par consquent, vous obtenez un message derreur similaire au suivant :
chmod: ne peut accder 'voix.mp3 musique planante.mp3 hit.mp3': Aucun
fichier ou rpertoire de ce type

La solution consiste employer la variable $@ et lentourer de guillemets. Sans les


guillemets, $* et $@ donnent le mme rsultat, mais, avec les guillemets, bash les traites de manire diffrente. Une rfrence $* donne alors lintgralit de la liste lintrieur dun seul jeu de guillemets, comme nous lavons fait jusqu prsent. En
revanche, une rfrence $@ ne produit pas une seule chane mais une liste de chanes
entre guillemets, une pour chaque argument.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.11. Compter les arguments

101

Utilisons $@ dans notre exemple de fichiers MP3 :


for NF in "$@"

Cette ligne est convertie en :


for NF in "voix.mp3" "musique planante.mp3" "hit.mp3"

Vous pouvez constater que le deuxime nom de fichier est maintenant plac entre
guillemets. Lespace fait partie de son nom et nest plus considre comme un sparateur
entre deux mots.
Lors du deuxime passage dans la boucle, $NF reoit la valeur musique planante.mp3,
qui comporte une espace. Vous devez donc faire attention lorsque vous utilisez $NF.
Vous devrez probablement la placer galement entre guillemets afin que lespace dans
le nom reste un lment de la chane et ne devienne pas un sparateur. Autrement dit,
vous devez employer "$NF" :
$ chmod 0750 "$NF"

Pourquoi ne pas toujours opter pour "$@" dans une boucle for ? Peut-tre parce que
cette expression est plus difficile saisir et que pour lcriture de scripts rapides, lorsque
vous savez que les noms des fichiers ne comportent pas despace, vous pouvez probablement garder lancienne syntaxe $*. En revanche, pour des scripts plus robustes, nous
vous recommandons de choisir "$@". Dans ce livre, ces deux variables sont employes
de manire quivalente, simplement parce que les vieilles habitudes ont la vie dure.

Voir aussi

la recette 5.8, Parcourir les arguments dun script, page 96 ;

la recette 5.9, Accepter les paramtres contenant des espaces, page 97 ;

la recette 5.12, Extraire certains arguments, page 103 ;

la recette 6.12, Boucler avec un compteur, page 135.

5.11. Compter les arguments


Problme
Vous avez besoin de connatre le nombre de paramtres passs au script.

Solution
Utilisez la variable du shell ${#}. Voici un script qui impose la prsence de trois arguments :
#!/usr/bin/env bash
# bash Le livre de recettes : verifier_nb_args
#
# Vrifier que le nombre d'arguments est correct :
# Utilisez la syntaxe donne ou bien if [ $# -lt 3 ]
if (( $# < 3 ))

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

102
then
printf
printf
exit 1
elif (( $#
then
printf
printf
exit 2
else
printf
fi

Chapitre 5 Variables du shell

"%b" "Erreur. Il manque des arguments.\n" >&2


"%b" "usage : monScript fichier1 op fichier2\n" >&2
> 3 ))
"%b" "Erreur. Il y a trop d'arguments.\n" >&2
"%b" "usage : monScript fichier1 op fichier2\n" >&2

"%b" "Nombre d'arguments correct. Traitement en cours...\n"

Voici un exemple de son excution, une premire fois avec trop darguments et une seconde fois avec le nombre darguments attendu :
$ ./monScript monFichier va ecraser votreFichier
Erreur. Il y a trop d'arguments.
usage : monScript fichier1 op fichier2
$ ./monScript monFichier ecrase votreFichier
Nombre d'arguments correct. Traitement en cours...

Discussion
Aprs les commentaires de dbut ( ne pas oublier dans un script), le test if vrifie si le
nombre darguments fournis (indiqu par $#) est suprieur trois. Si cest le cas, nous
affichons un message derreur, rappelons lutilisateur la bonne utilisation et quittons
le script.
Les messages derreur sont redirigs vers lerreur standard. Nous respectons ainsi le rle
de lerreur standard comme canal de transport des messages derreur.
La valeur de retour du script est galement diffrente selon lerreur dtecte. Bien que
ce fonctionnement ne soit pas trs important dans ce cas, il devient utile lorsquun script
peut tre invoqu par dautres scripts. Il est ainsi possible de dtecter les erreurs (grce
une valeur de retour diffrente de zro) mais galement de diffrencier les types derreurs.
Attention : ne confondez pas ${#} avec ${#VAR} ou ${VAR#alt}, uniquement parce
quelles utilisent toutes le caractre # entre des accolades. La premire donne le nombre
darguments, la deuxime la longueur de la valeur de la variable VAR et la troisime une
certaine forme de substitution.

Voir aussi

la recette 4.2, Connatre le rsultat de lexcution dune commande, page 73 ;

la recette 5.1, Documenter un script, page 87 ;

la recette 5.12, Extraire certains arguments, page 103 ;

la recette 5.18, Modifier certaines parties dune chane, page 109 ;

la recette 6.12, Boucler avec un compteur, page 135.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.12. Extraire certains arguments

103

5.12. Extraire certains arguments


Problme
Tout script shell digne de ce nom aura deux sortes darguments : des options qui modifient le comportement du script et les arguments rellement utiliss pour laccomplissement de son objectif. Vous avez besoin dun mcanisme permettant denlever les
arguments reprsentant des option, aprs les avoir analyss.
Reprenons le script suivant :
for NF in "$@"
do
echo modification de $NF
chmod 0750 "$NF"
done

Il est trs simple. Il affiche le nom du fichier sur lequel il travaille, puis il en modifie les
autorisations. Cependant, vous aimeriez parfois quil naffiche pas le nom du fichier.
Comment pouvez-vous ajouter une option qui dsactive ce comportement prolixe tout
en conservant la boucle for ?

Solution
#!/usr/bin/env bash
# bash Le livre de recettes : utiliser_option
#
# Utilise et extrait une option.
#
# Analyse l'argument facultatif.
VERBEUX=0;
if [[ $1 = -v ]]
then
VERBEUX=1;
shift;
fi
#
# Le vrai travail se fait ici.
#
for NF in "$@"
do
if (( VERBEUX == 0 ))
then
echo modification de $NF
fi
chmod 0750 "$NF"
done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

104

Chapitre 5 Variables du shell

Discussion
Nous avons ajout une variable doption, $VERBEUX, pour prciser si le nom du fichier
doit tre affich avant la modification des autorisations. Cependant, une fois que le
script a vu le paramtre -v et fix la variable VERBEUX, -v ne doit plus faire partie de la
liste des arguments. Linstruction shift demande bash de dcaler ses arguments dune
position vers le bas. Le premier argument ($1) est cart et $2 devient $1, $3 devient $2,
etc.
Ainsi, lors de lexcution de la boucle for, la liste des arguments (dans $@) ne contient
plus loption -v mais dbute directement avec le paramtre suivant.
Cette approche est bien adapte la gestion dune seule option. En revanche, lorsquelles sont plus nombreuses, vous avez besoin dun mcanisme un peu plus labor. Par
convention, les options dun script shell ne dpendent pas (en gnral) dun emplacement. Par exemple, monScript -a -p doit tre quivalent monScript -p -a. Par ailleurs,
un script robuste doit tre en mesure de grer les rptitions doptions et les ignorer ou
afficher une erreur. La recette 13.1, page 257, prsentera une analyse plus robuste des options base sur la commande getopts de bash.

Voir aussi

help shift ;

la recette 5.8, Parcourir les arguments dun script, page 96 ;

la recette 5.11, Compter les arguments, page 101 ;

la recette 5.12, Extraire certains arguments, page 103 ;

la recette 6.15, Analyser les arguments de la ligne de commande, page 139

la recette 13.1, Analyser les arguments dun script, page 257 ;

la recette 13.2, Afficher ses propres messages derreur lors de lanalyse, page 260.

5.13. Obtenir des valeurs par dfaut


Problme
Votre script shell attend des arguments sur la ligne de commande. Vous aimeriez fournir des valeurs par dfaut afin que les valeurs les plus courantes puissent tre utilises
sans les saisir chaque invocation.

Solution
Utilisez la syntaxe ${:-} lors des rfrences aux paramtres pour donner une valeur par
dfaut :
REP_FICHIER=${1:-"/tmp"}

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.14. Fixer des valeurs par dfaut

105

Discussion
Plusieurs oprateurs spciaux peuvent tre employs dans les rfrences aux variables
du shell. Celui utilis prcdemment, loprateur :-, signifie que si la variable $1 nest
pas fixe ou si elle est nulle, il faut alors prendre la valeur indique ensuite, cest--dire
/tmp dans notre exemple. Dans le cas contraire, il faut prendre la valeur qui se trouve
dj dans $1. Cet oprateur peut tre utilis avec nimporte quelle variable du shell, pas
uniquement avec les paramtres positionnels (1, 2, 3, etc.), mme sil sagit de son usage
le plus frquent.
Bien entendu, vous pouvez obtenir le mme rsultat avec une instruction if qui vrifie
si la variable est nulle ou si elle est indfinie (nous laissons cet exercice au lecteur), mais
ce type de contrle est tellement frquent dans les scripts que cette syntaxe est un raccourci bienvenu.

Voir aussi

la page de manuel de bash sur la substitution des paramtres ;

Le shell bash de Cameron Newham (ditions OReilly), pages 9192 ;

Introduction aux scripts shell de Nelson H.F. Beebe et Arnold Robbins (ditions
OReilly), pages 115116 ;

la recette 5.14, Fixer des valeurs par dfaut, page 105.

5.14. Fixer des valeurs par dfaut


Problme
Votre script doit sappuyer sur certaines variables denvironnement, quil sagisse de celles frquemment utilises (par exemple $USER) ou de celles propres votre projet. Si
vous voulez crire un script shell robuste, vous devez vrifier que ces variables ont une
valeur correcte. Comment pouvez-vous assurer que cest bien le cas ?

Solution
Utilisez loprateur daffectation dans la premire rfrence une variable du shell afin
dattribuer une valeur cette variable si elle nest pas dj dfinie :
cd ${HOME:=/tmp}

Discussion
Dans lexemple prcdent, la rfrence $HOME retourne la valeur actuelle de la variable
$HOME, except si elle est vide ou si elle nest pas dfinie. Dans ces deux situations, la valeur /tmp est retourne et affecte $HOME afin que les prochaines rfrences cette variable retournent cette nouvelle valeur.
Voici ce principe en action :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

106

Chapitre 5 Variables du shell

$ echo ${HOME:=/tmp}
/home/uid002
$ unset HOME
# En gnral, viter.
$ echo ${HOME:=/tmp}
/tmp
$ echo $HOME
/tmp
$ cd ; pwd
/tmp
$

Lappel unset retire toute valeur la variable. Ensuite, lorsque nous utilisons loprateur := dans la rfrence cette variable, la nouvelle valeur (/tmp) lui est attribue. Les
rfrences ultrieures $HOME retournent cette nouvelle valeur.
Vous ne devez pas oublier lexception suivante concernant loprateur daffectation : ce
mcanisme ne fonctionne pas avec les paramtres positionnels (par exemple, $1 ou $*).
Dans ce cas, utilisez :- dans des expressions de la forme ${1:-defaut} qui retourneront
la valeur sans tenter laffectation.
Pour mmoriser ces symboles sotriques, vous pouvez vous aider de la diffrence visuelle entre ${VAR:=valeur} et ${VAR:-valeur}. La variante := ralise une affectation
et retourne la valeur place droite de loprateur. La variante :- ne fait que la moiti
de ce travail elle retourne uniquement la valeur sans procder laffectation puisque le symbole nest que la moiti du signe gal (une barre horizontale la place de
deux barres). Si cela ne vous aide pas, oubliez-le.

Voir aussi

la recette 5.13, Obtenir des valeurs par dfaut, page 104.

5.15. Utiliser null comme valeur par dfaut


valide
Problme
Vous devez fixer une valeur par dfaut, mais vous souhaitez que la chane vide soit accepte. La valeur par dfaut ne doit servir que dans le cas o la variable nest pas dfinie.
Avec loprateur ${:=}, la nouvelle valeur est choisie dans deux cas : lorsque la valeur
de la variable du shell na pas t pralablement fixe (ou a t explicitement retire) et
lorsque la valeur a t fixe mais est vide, par exemple HOME="" ou HOME=$AUTRE ( $AUTRE
nayant pas de valeur).

Solution
Le shell peut diffrencier ces deux cas. En retirant les deux-points (:), vous indiquez que
la substitution ne doit avoir lieu que si la valeur nest pas fixe. Si vous crivez simplement
${HOME=/tmp}, sans les deux-points, laffectation se fera uniquement dans le cas o la variable ne contient pas de valeur (na jamais t fixe ou a t explicitement indfinie).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.16. Indiquer une valeur par dfaut variable

107

Discussion
Amusons-nous nouveau avec la variable $HOME, mais, cette fois-ci, sans les deux-points
de loprateur :
$ echo ${HOME=/tmp} # La substitution nest pas ncessaire.
/home/uid002
$ HOME=""
# En gnral, viter.
$ echo ${HOME=/tmp} # La substitution na pas lieu.
$ unset HOME
# En gnral, viter.
$ echo ${HOME=/tmp} # La substitution a lieu.
/tmp
$ echo $HOME
/tmp
$

Lorsque nous affectons une chane vide la variable $HOME, loprateur = ne procde pas
la substitution car $HOME a bien une valeur, mme si elle est nulle. En revanche, lorsque nous supprimons la dfinition de la variable, la substitution a lieu. Si vous souhaitez autoriser les chanes vides, utilisez loprateur =, sans les deux-points. Cependant, :=
est plus souvent employ car vous ne pouvez pas faire grand-chose avec une valeur vide,
que ce soit dlibr ou non.

Voir aussi

la recette 5.13, Obtenir des valeurs par dfaut, page 104 ;

la recette 5.14, Fixer des valeurs par dfaut, page 105.

5.16. Indiquer une valeur par dfaut variable


Problme
Vous avez besoin que la valeur par dfaut de la variable ne soit pas une constante.

Solution
La partie droite des rfrences aux variables du shell peut tre un peu plus labore
quune simple constante. Par exemple :
cd ${BASE:="$(pwd)"}

Discussion
Comme le montre lexemple, la valeur de remplacement nest pas ncessairement une
chane constante. Il peut sagir du rsultat dune expression plus complexe, y compris
issue de lexcution de commandes dans un sous-shell. Dans notre exemple, si la variable $BASE nest pas fixe, le shell excute la commande interne pwd (pour obtenir le rpertoire de travail) et affecte la chane gnre la variable.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

108

Chapitre 5 Variables du shell

Que pouvez-vous donc placer sur la partie droite de loprateur (et des autres oprateurs
similaires) ? La page de manuel de bash stipule que le contenu de la partie droite de
loprateur est soumis lexpansion du tilde, lexpansion des paramtres, la substitution de commandes et lexpansion arithmtique .
Voici ce que cela signifie :

lexpansion des paramtres vous permet dutiliser dautres variables du shell dans
lexpression : ${BASE:=${HOME}} ;

lexpansion du tilde signifie quune expression comme ~bob est reconnue et remplace par le rpertoire personnel de lutilisateur bob. Utilisez ${BASE:=~uid17} pour
que la valeur par dfaut soit le rpertoire personnel de lutilisateur uid17, mais ne
placez pas cette chane entre guillemets car ils annulent lexpansion du tilde ;

la substitution de commandes a t employe dans lexemple. Elle excute les commandes et affectent leur sortie la variable. Les commandes sont incluses entre les
parenthses, cest--dire $( commandes ) ;

lexpansion arithmtique vous permet deffectuer une arithmtique entire dans


lexpression, en utilisant la syntaxe $(( ... )). En voici un exemple :
echo ${BASE:=/home/uid$((ID+1))}

Voir aussi

la recette 5.13, Obtenir des valeurs par dfaut, page 104.

5.17. Afficher un message derreur pour les


paramtres non dfinis
Problme
Tous ces raccourcis pour prciser une valeur par dfaut sont bien pratiques, mais vous
voulez obliger les utilisateurs donner des valeurs, sans quoi le traitement ne peut pas
se poursuivre. Sils ont oubli un paramtre, cest peut-tre parce quils ne comprennent
pas vraiment lutilisation de votre script. Vous ne voulez rien laisser au hasard. Vous recherchez donc un moyen, autre quune suite dinstructions if, pour vrifier chacun des
nombreux paramtres.

Solution
Utilisez la syntaxe ${:?} lors dune rfrence a un paramtre. bash affichera un message
derreur et quittera le script si le paramtre nest pas fix ou sil est nul.
#!/usr/bin/env bash
# bash Le livre de recettes : verifier_params_indefinis
#
USAGE="usage : monScript rpertoire fichierSource conversion"
REP_FICHIER=${1:?"Erreur. Vous devez indiquer un rpertoire initial."}
FICHIER_SRC=${2:?"Erreur. Vous devez fournir un fichier source."}
TYPE_CONV=${3:?"Erreur. ${USAGE}"}

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.18. Modifier certaines parties dune chane

109

Voici un exemple dexcution du script avec des paramtres insuffisants :


$ ./monScript /tmp /dev/null
./monScript: line 5: 3: Erreur. usage: monScript rpertoire fichierSource
conversion
$

Discussion
Le contrle consiste vrifier si le premier paramtre est fix (ou nul). Dans le cas contraire, il affiche un message derreur et quitte le script.
La troisime variable utilise une autre variable du shell dans son message. Vous pouvez
mme y excuter une autre commande :
TYPE_CONV=${3:?"Erreur. $USAGE. $(rm $REP_FICHIER)"}

Si le troisime paramtre nest pas fix, le message derreur contient la phrase


Erreur. , suivie de la valeur de la variable $USAGE et de toute sortie gnre par la
commande qui supprime le fichier indiqu par la variable $REP_FICHIER. Cest vrai, l
nous nous laissons un peu emporter. Vous pouvez rendre votre script shell affreusement
compact. Il est prfrable de gaspiller un peu despace et quelques octets pour que sa logique soit plus claire :
if [ -z "$3" ]
then
echo "Erreur. $USAGE"
rm $REP_FICHIER
fi

Voici une autre remarque : le message derreur produit par ${:?} inclut le nom de fichier du script shell et un numro de ligne. Par exemple :
./monScript: line 5: 3: Erreur. usage: monScript rpertoire fichierSource
conversion

Puisque nous navons aucun moyen dagir sur cette partie du message et puisquelle ressemble une erreur dans le script shell lui-mme, sans mentionner le problme de lisibilit, cette technique nest pas trs rpandue dans les scripts shell de qualit
industrielle. Elle peut cependant savrer trs utile pour le dbogage.

Voir aussi

la recette 5.13, Obtenir des valeurs par dfaut, page 104 ;

la recette 5.14, Fixer des valeurs par dfaut, page 105 ;

la recette 5.16, Indiquer une valeur par dfaut variable, page 107.

5.18. Modifier certaines parties dune chane


Problme
Vous souhaitez renommer tout un ensemble de fichiers. Les noms des fichiers sont correctement traits, mais pas leurs extensions.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

110

Chapitre 5 Variables du shell

Solution
Utilisez lexpansion des paramtres de bash, qui retire le texte correspondant un motif.
#!/usr/bin/env bash
# bash Le livre de recettes : suffixer
#
# Renommer les fichiers *.bof en *.bash.
for NF in *.bof
do
mv "${NF}" "${NF%bof}bash"
done

Discussion
La boucle for parcourt la liste des fichiers du rpertoire de travail dont les noms se terminent par .bof. La variable $NF prend successivement la valeur de chaque nom. lintrieur de la boucle, la commande mv renomme le fichier (le dplace de lancien nom
vers le nouveau nom). Nous plaons chaque nom de fichier entre guillemets pour le cas
o lun deux contiendrait des espaces.
Llment central de cette opration rside dans la rfrence $NF qui inclut une suppression automatique des caractres bof de fin. La notation ${ } dlimite la rfrence
pour que le terme bash qui suit soit ajout immdiatement la fin de la chane.
Voici le fonctionnement dcompos en plusieurs tapes :
SANS_BOF="${NF%bof}"
NOUVEAU_NOM="${SANS_BOF}bash"
mv "${NF}" "${NOUVEAU_NOM}"

Vous pouvez ainsi voir les diffrentes phases de suppression du suffixe indsirable, de la
cration du nouveau nom et du renommage du fichier. Cependant, runir toutes ces
tapes sur une seule ligne est intressant, une fois les oprateurs spciaux bien compris.
Outre la suppression dune sous-chane de la variable, nous remplaons galement bof
par bash. Par consquent, nous pouvons utiliser loprateur de substitution pour les rfrences de variable, cest--dire la barre oblique (/). De manire similaire aux commandes dun diteur (par exemple, celles disponibles dans vi et sed) qui utilisent la barre
oblique pour dlimiter les substitutions, voici une autre version de la conversion :
mv "${NF}" "${NF/.bof/.bash}"

Contrairement aux commandes de ces diteurs, la barre oblique finale est absente car
son rle est jou par laccolade fermante.
Cependant, nous navons pas choisi cette approche car elle ne permet pas dancrer la
substitution, qui se produit donc nimporte o dans la variable. Par exemple, si un fichier se nomme boboffert.bof, la substitution donne donc bobashfert.bof, ce qui ne correspond pas vraiment ce que nous voulions. En utilisant une double barre oblique la
place de la premire, toutes les occurrences dans la variable seraient remplaces. Nous
obtiendrions alors bobashfert.bash, ce qui nest pas mieux.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

5.19. Utiliser les tableaux

111

Le tableau 5-1 prsente les diffrents oprateurs de manipulation du contenu des variables au sein des rfrences. Testez-les tous, ils sont trs utiles.
Tableau 5-1. Oprateurs de manipulation de chanes
lintrieur de ${ ... }

Action effectue

nom:dbut:longueur

Retourne la sous-chane commenant dbut et ayant la longueur indique.

#nom

Retourne la longueur de la chane.

nom#motif

Supprime le (plus court) motif partir du dbut.

nom##motif

Supprime le (plus long) motif partir du dbut.

nom%motif

Supprime le (plus court) motif partir de la fin.

nom%%motif

Supprime le (plus long) motif partir de la fin.

nom/motif/chane

Remplace la premire occurrence.

nom//motif/chane

Remplace toutes les occurrences.

Voir aussi

man rename ;

la recette 12.5, Comparer deux documents, page 254.

5.19. Utiliser les tableaux


Problme
Nous avons prsent de nombreux scripts avec des variables, mais bash peut-il prendre
en charge un tableau de variables ?

Solution
Oui. bash dispose prsent dune syntaxe pour les tableaux une dimension.

Description
Les tableaux sont faciles initialiser si vous en connaissez les valeurs au moment de
lcriture du script. Voici le format employer :
MONTAB=(premier deuxime troisime quatrime)

Chaque lment du tableau est un mot spar de la liste incluse entre les parenthses.
Ensuite, vous pouvez faire rfrence chacun de ces lments de la manire suivante :
echo les ${MONTAB[0]} et ${MONTAB[2]} coureurs

La sortie est alors :


les premier et troisime coureurs

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

112

Chapitre 5 Variables du shell

Si vous crivez simplement $MONTAB, vous obtenez uniquement le premier lment,


comme si vous aviez utilis ${MONTAB[0]}.

Voir aussi

Le shell bash de Cameron Newham (ditions OReilly), pages 158162, pour plus
dinformations sur les tableaux.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6
Logique et arithmtique

Larithmtique constitue lune des principales volutions des versions modernes de bash
par rapport au shell Bourne originel. Les premires versions de linterprteur de commandes taient incapables dune quelconque arithmtique. Il fallait invoquer un programme spar, mme pour ajouter 1 une variable. En un sens, cest un tribut la
versatilit et la puissance du shell ; il peut servir normment de tches, malgr sa pitre prise en charge de larithmtique. ce moment-l, personne nimaginait que le shell
pourrait tre aussi utile et aussi employ. Cependant, lautomatisation des tches rptitives, par un simple mcanisme de comptage, a rvl le besoin dune syntaxe simple
et directe pour larithmtique. Son absence dans le shell Bourne originel a largement
contribu au succs du shell C (csh) lorsque quil a propos un syntaxe de programmation similaire celle du langage C, notamment pour les variables numriques. Mais
tout cela a bien volu. Si vous navez pas utilis larithmtique de bash depuis un moment, vous risquez dtre fort surpris.
Outre larithmtique, bash dispose des structures de contrle familires tous les programmeurs. La construction if/then/else permet de prendre des dcisions. Les boucles
while et for sont galement prsentes, mais vous verrez que bash y ajoute quelques particularits. Linstruction case offre de nombreuses possibilits, grce sa correspondance de motif. Il existe aussi une construction assez trange, nomme select. Aprs avoir
pass en revue toutes ces fonctionnalits, nous terminerons ce chapitre par le dveloppement de deux calculatrices simples en ligne de commande.

6.1. Utiliser larithmtique dans un script


Problme
Vous avez besoin deffectuer quelques calculs simples dans votre script.

Solution
Utilisez $(( )) ou let pour les expressions arithmtiques entires.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

114

Chapitre 6 Logique et arithmtique

TOTAL=$((TOTAL + 5 + MAX * 2))


let TOTAL+=5+MAX*2

Discussion
Tant que les oprations se font en arithmtique entire, vous pouvez employer tous les
oprateurs standard (de type C) lintrieur de $(( )). Vous disposez galement dun
oprateur, **, pour calculer une puissance. Par exemple, MAX=$((2**8)) donne 256.
Les espaces ne sont pas ncessaires, ni interdites, autour des oprateurs et des arguments
dans une expression $(( )) (mais les deux astrisques de ** doivent tre colls). En revanche, vous ne pouvez pas placer despace autour du signe gal, comme cest le cas
pour toute affectation de variables bash. Si vous crivez la ligne suivante :
TOTAL

= $((TOTAL + 5))

# Ne donne pas le rsultat escompt !

bash tente dexcuter un programme nomm TOTAL, dont le premier argument est un
signe gal et le deuxime le rsultat de la somme de 5 et de $TOTAL. Noubliez pas de
retirer toute espace qui pourrait se trouver autour du signe gal.
Pour obtenir la valeur dune variable, vous placez normalement le symbole $ devant
son nom (par exemple, $TOTAL ou $MAX). Cependant, cela nest pas ncessaire lintrieur des doubles parenthses. Par exemple, dans lexpression $((TOTAL +5 MAX * 2)), le
symbole dollar nest pas obligatoire devant le nom des variables du shell. En effet, le caractre $ plac lextrieur des parenthses sapplique lexpression entire.
En revanche, pour utiliser un paramtre positionnel (par exemple, $2), il est ncessaire
dajouter le symbole $ afin de le diffrencier dune constante numrique (par exemple,
2) :
TOTAL=$((TOTAL + $2 + DECALAGE))

Linstruction let interne bash apporte un mcanisme similaire pour effectuer une
arithmtique entire avec les variables du shell. Elle emploie les mmes oprateurs
arithmtiques que la construction $(( )) :
let TOTAL=TOTAL+5

En revanche, elle fournit dautres oprateurs daffectation plus exotiques. Par exemple,
la ligne suivante est quivalente la prcdente :
let TOTAL+=5

Elle devrait tre familire aux programmeurs C/C++ et Java.


Le tableau 6-1 donne la liste de ces oprateurs daffectation particuliers.
Tableau 6-1. Les oprateurs daffectation de bash
Oprateur

Opration en plus de
laffectation

Utilisation

Signification

affectation simple

a=b

a=b

*=

multiplication

a*=b

a=(a*b)

/=

division

a/=b

a=(a/b)

%=

reste

a%=b

a=(a%b)

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.1. Utiliser larithmtique dans un script

115

Tableau 6-1. Les oprateurs daffectation de bash (suite)


Oprateur

Opration en plus de
laffectation

Utilisation

Signification

+=

addition

a+=b

a=(a+b)

-=

soustraction

a-=b

a=(a-b)

<<=

dcalage dun bit gauche

a<<=b

a=(a<<b)

>>=

dcalage dun bit droite

a>>=b

a=(a>>b)

&=

Et binaire

a&=b

a=(a&b)

^=

Ou exclusif binaire

a^=b

a=(a^b)

|=

Ou binaire

a|=b

a=(a|b)

Ces oprateurs daffectation sont galement disponibles dans la construction $(( )),
condition quils soient placs intrieur des doubles parenthses. Le premier oprateur
correspond strictement laffectation dune variable shell.
Les affectations peuvent galement tre effectues en cascade, par le biais de loprateur
virgule :
echo $(( X+=5 , Y*=3 ))

Dans cet exemple, les deux affectations sont ralises et le rsultat de la seconde expression est affich, car loprateur virgule retourne la valeur de sa deuxime expression. Si
vous ne voulez pas afficher le rsultat, il suffit dutiliser linstruction let :
let

X+=5 Y*=3

Loprateur virgule est inutile ici car chaque mot dune instruction let constitue une
expression arithmtique en soi.
En gnral, dans les scripts bash, certains caractres ont des significations particulires,
par exemple lastrisque pour les motifs gnriques ou les parenthses pour lexcution
dun sous-shell. En revanche, dans les instructions let ou les constructions $(( )), ils
perdent leur signification spciale et il est donc inutile dutiliser les guillemets ou les
barres obliques inverses pour les chapper :
let Y=(X+2)*10
Y=$(( ( X + 2 ) * 10 ))

Linstruction let et la construction $(( )) diffrent galement sur un autre point, la


gestion des espaces. Linstruction let exige quil ny ait aucune espace autour de loprateur daffectation (le signe gal), ainsi quautour des autres oprateurs. Lintgralit de
lexpression arithmtique doit constituer un seul mot.
En revanche, la construction $(( )) est plus tolrante et accepte les espaces lintrieur
des parenthses. Elle est donc moins sujette aux erreurs et le code est plus facile lire.
Il sagit de notre solution prfre pour effectuer une arithmtique entire dans bash.
Cependant, nous faisons une exception pour laffectation += occasionnelle ou loprateur ++, ou bien lorsque nous devenons nostalgiques des beaux jours de la programmation en BASIC (avec son instruction LET).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

116

Chapitre 6 Logique et arithmtique

Attention, il sagit dune arithmtique entire et non en virgule flottante. Une expression comme 2/3 donne donc la valeur 0 (zro). La
division se fait sur des entiers et supprime donc la partie dcimale.

Voir aussi

help let ;

la page de manuel de bash.

6.2. Conditionner lexcution du code


Problme
Vous souhaitez vrifier que le nombre darguments est correct et prendre des dcisions
diffrentes selon le rsultat du test. Vous avez besoin dune construction de branchement.

Solution
Linstruction if de bash est similaire celle des autres langages de programmation :
if [ $# -lt 3 ]
then
printf "%b" "Erreur. Il manque des arguments.\n"
printf "%b" "usage : monScript fichier1 op fichier2\n"
exit 1
fi

Ou bien :
if (( $# < 3 ))
then
printf "%b" "Erreur. Il manque des arguments.\n"
printf "%b" "usage : monScript fichier1 op fichier2\n"
exit 1
fi

Voici une combinaison complte dinstruction if, avec une clause elif (version bash de
else-if) et une clause else :
if (( $# <
then
printf
printf
exit 1
elif (( $#
then
printf
printf

[05/03/08]

bash Le livre de recettes

3 ))
"%b" "Erreur. Il manque des arguments.\n"
"%b" "usage : monScript fichier1 op fichier2\n"
> 3 ))
"%b" "Erreur. Il y a trop darguments.\n"
"%b" "usage : monScript fichier1 op fichier2\n"

Elodie FRITSCH <elodie.fritsch@total.com>

6.2. Conditionner lexcution du code

117

exit 2
else
printf "%b" "Nombre darguments correct. Traitement en cours...\n"
fi

Vous pouvez mme crire du code comme celui-ci :


[ $resultat = 1 ] \
&& { echo "Le rsultat est 1 ; excellent." ; exit 0;
|| { echo "Ouh l l, disparaissez ! " ; exit 120; }

} \

(Pour une explication de ce dernier exemple, consultez la recette 2.14, page 44.)

Discussion
Nous devons examiner deux aspects : la structure de base dune instruction if et la raison de ses diffrentes syntaxes (parenthses ou crochets, oprateurs ou options). Le premier peut expliquer le second. Voici la forme gnrale dune instruction if (daprs la
page de manuel de bash) :
if liste; then liste; [ elif liste; then liste; ] ... [ else liste; ] fi

Les caractres [ et ] de notre description servent dlimiter les parties facultatives de


linstruction (par exemple, certaines instructions if nont pas de clause else). Commenons par examiner la version de if sans les lments facultatifs.
Voici la forme la plus simple dune instruction if :
if liste; then liste; fi
Dans bash, le point-virgule joue le mme rle que le saut de ligne ; il
termine une instruction. Dans les premiers exemples de la section Solution, nous aurions donc pu rendre les exemples plus concis en utilisant
des points-virgules, mais les sauts de ligne amliorent leur lisibilit.

Si lon sen rfre aux autres langages de programmation, le sens de la partie then liste
semble clair il sagit des instructions qui seront excutes lorsque la condition du if
svalue vrai. En revanche, quen est-il de if liste ? Nous sommes plutt habitus if
expression.
Noubliez pas que nous sommes dans un shell, cest--dire un interprteur de commandes. Son rle principal est dexcuter des commandes. Par consquent, la partie liste
qui se trouve aprs if contient une liste de commandes. Dans ce cas, quel est llment
qui permet de dterminer le branchement (lexcution de then ou de else) ? Il sagit
tout simplement de la valeur de retour de la dernire commande de la liste. Cette valeur, comme vous devez vous en souvenir, est galement disponible dans la variable $?.
Pour illustrer ce point, prenons un exemple un peu trange :
$ cat essayerCeci.sh
if ls; pwd; cd $1;
then
echo succs;
else

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

118

Chapitre 6 Logique et arithmtique


echo chec;

fi
pwd
$ bash ./essayerCeci.sh /tmp
...
$ bash ./essayerCeci.sh /inexistant
...
$

Dans ce script est un peu bizarre, le shell excute trois commandes (ls, pwd et cd) avant
deffectuer le branchement. Largument de la commande cd est le premier fourni lors
de linvocation du script. Sil est absent, le shell excute simplement cd, qui ramne
dans le rpertoire personnel.
Comment cela fonctionne-t-il ? Laffichage de succs ou de chec dpend de la
russite de la commande cd. Dans notre exemple, cd est la dernire commande de la liste donne if. Si elle choue, la clause else est slectionne. En revanche, si elle russit,
la clause then est choisie.
Les commandes bien crites et les commandes internes retournent la valeur 0 (zro)
lorsquelles ne rencontrent aucune erreur pendant leur excution. Si elles dtectent un
problme, par exemple un paramtre erron, des erreurs dentre/sortie ou un fichier
non trouv, elles retournent une valeur diffrente de zro (et souvent une valeur diffrente pour chaque type derreur dtecte).
Cest pourquoi il est important que les dveloppeurs de scripts shell et de programmes
C (ou en dautres langages) sassurent que les valeurs retournes par leur code sont significatives. Le bon fonctionnement dune instruction if dune autre personne pourrait en dpendre !
Voyons maintenant comment nous pouvons passer de cette construction if, un tantinet trange, une instruction if plus habituelle, comme on la rencontre gnralement
dans les programmes. Cest le cas dans les exemples montrs au dbut de cette recette.
En effet, ils ne ressemblent pas vraiment une liste dinstructions.
Essayons le code suivant qui implique le test dune taille :
if test $# -lt 3
then
echo recommencez.
fi

Remarquez-vous ce qui pourrait ressembler, sinon une liste complte, tout au moins
une seule commande shell ? La commande interne test, qui compare les valeurs de ses
arguments, retourne 0 lorsque son valuation est vraie, 1 sinon. Pour le constater par
vous-mme, essayez la commande test sur une ligne et vrifiez sa valeur de retour avec
echo $?.
Notre premier exemple, qui commenait par if [ $# -lt 3 ], ressemble fortement celui bas sur linstruction test. En effet, [ est en ralit la commande test, cest--dire juste
un autre nom pour la mme commande. Lorsque vous utilisez le nom [, il faut galement un ] en dernier paramtre, pour des raisons de lisibilit et desthtisme. Cela explique donc la premire syntaxe : lexpression de linstruction if est en ralit une liste
dune seule commande, test.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.3. Tester les caractristiques des fichiers

119

Dans les premires versions dUnix, test tait un excutable spar et


[ un lien vers cet excutable. Ils existent encore sous forme de programmes excutables dans dautres shells, mais bash a choisi den
faire des commandes internes.

prsent, examinons lexpression if (( $# < 3 )) utilise dans le deuxime exemple de


la section Solution. Les doubles parenthses font partie des commandes combines. Elles
sont utiles dans les instructions if car elles effectuent une valuation arithmtique de
lexpression quelles contiennent. Il sagit dune amlioration rcente de bash, ajoute
spcialement pour les cas dutilisation comme dans les instructions if.
Les distinctions importantes entre les deux formes de syntaxe utilises dans une instruction if rsident dans lexpression des tests et les aspects tests. Les doubles parenthses
sont strictement des expressions arithmtiques. Les crochets peuvent galement tester
certaines caractristiques de fichiers, mais leur syntaxe est moins adapte aux expressions arithmtiques. Cest dautant plus vrai lorsque vous regroupez de longues expressions avec des parenthses (qui doivent tre places entre guillemets ou chappes).

Voir aussi

help if ;

help test ;

man test ;

la recette 2.14, Enregistrer ou runir la sortie de plusieurs commandes, page 44 ;

la recette 4.2, Connatre le rsultat de lexcution dune commande, page 73 ;

la recette 6.3, Tester les caractristiques des fichiers, page 119 ;

la recette 6.5, Tester les caractristiques des chanes, page 123 ;

la recette 15.11, Obtenir lentre depuis une autre machine, page 354.

6.3. Tester les caractristiques des fichiers


Problme
Vous souhaitez rendre votre script robuste en vrifiant que le fichier dentre existe
avant de le lire, que vous avez les droits dcriture sur le fichier de sortie ou quun rpertoire existe avant dinvoquer cd. Comment effectuer tous ces contrles dans un script
bash ?

Solution
Utilisez les possibilits de vrification des caractristiques de fichiers offertes par la commande test dans des instructions if. Vos problmes particuliers peuvent tre rsolus par
des scripts ressemblant celui-ci :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

120

Chapitre 6 Logique et arithmtique

#!/usr/bin/env bash
# bash Le livre de recettes : verifier_fichier
#
REP=/tmp
FICHIER_ENTREE=/home/yucca/donnees.reelles
FICHIER_SORTIE=/home/yucca/autres.resultats
if [ -d "$REP" ]
then
cd $REP
if [ -e "$FICHIER_ENTREE" ]
then
if [ -w "$FICHIER_SORTIE" ]
then
calculer < "$FICHIER_ENTREE" >> "$FICHIER_SORTIE"
else
echo "Impossible d'crire dans $FICHIER_SORTIE"
fi
else
echo "Impossible de lire depuis $FICHIER_ENTREE"
fi
else
echo "Impossible d'aller dans $REP"
fi

Discussion
Nous plaons toutes les rfrences aux diffrents fichiers entre guillemets pour le cas o
les chemins contiendraient des espaces. Il ny en a pas dans cet exemple, mais ce sera
peut-tre le cas si vous modifiez le chemin.
Nous testons puis excutons la commande cd avant les deux autres conditions. Dans cet
exemple, cela na pas vraiment dimportance, mais si FICHIER_ENTREE ou FICHIER_SORTIE
taient des chemins relatifs (qui ne dbutent pas la racine du systme de fichiers, cest-dire sans commencer par / ), le test peut svaluer vrai avant cd et faux aprs, ou
vice versa. En procdant ainsi, le test est effectu juste avant lutilisation des fichiers.
Loprateur >> nous permet dajouter la sortie dans le fichier des rsultats, sans lcraser.
Si vous deviez le remplacer, les autorisations dcriture sur ce fichier nauraient pas besoin dtre testes car vous auriez alors uniquement besoin dune autorisation dcriture
sur le rpertoire qui le contient.
Lensemble des tests peut tre combin dans une longue instruction if en utilisant
loprateur -a, mais, en cas dchec, il est impossible de donner un message derreur utile car vous ne savez de quel test vient le problme.
Vous pouvez galement tester dautres caractristiques. Trois dentre elles utilisent des
oprateurs ordinaires, chacun attendant deux noms de fichiers :
FICHIER1 -nt FICHIER2
Est plus rcent que (en fonction de la date de dernire modification).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.3. Tester les caractristiques des fichiers

121

FICHIER1 -ot FICHIER2


Est plus ancien que.
FICHIER1 -ef FICHIER2
Ont le mme numro de priphrique et dinode (fichier identique, mme sil
sagit de liens diffrents).
Le tableau 6-2 dcrit les autres tests associs aux fichiers (la section Oprateurs de test,
page 536, donne une liste plus complte). Il sagit uniquement doprateurs unaires qui
prennent la forme option nomFichier, par exemple if [ -e monFichier ].
Tableau 6-2. Oprateurs unaires pour le test des caractristiques de fichiers
Option

Description

-b

Le fichier est un priphrique en mode bloc (comme /dev/hda1).

-c

Le fichier est un priphrique en mode caractre (comme /dev/tty).

-d

Le fichier est un rpertoire.

-e

Le fichier existe.

-f

Le fichier est un fichier normal.

-g

Le bit SGID (set group ID) du fichier est positionn.

-h

Le fichier est un lien symbolique (identique -L).

-G

Le fichier appartient lidentifiant de groupe rel.

-k

Le bit sticky du fichier est positionn.

-L

Le fichier est un lien symbolique (identique -h).

-O

Le fichier appartient lidentifiant dutilisateur rel.

-p

Le fichier est un tube nomm.

-r

Le fichier peut tre lu.

-s

Le fichier nest pas vide (sa taille est suprieure zro).

-S

Le fichier est une socket.

-u

Le bit SUID (set user ID) du fichier est positionn.

-w

Le fichier peut tre modifi.

-x

Le fichier peut tre excut.

Voir aussi

la recette 2.10, Ajouter la sortie un fichier existant, page 41 ;

la recette 4.6, Utiliser moins dinstructions if, page 78 ;

la section Oprateurs de test, page 536.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

122

Chapitre 6 Logique et arithmtique

6.4. Tester plusieurs caractristiques


Problme
Comment pouvez-vous tester plusieurs caractristiques ? Faut-il imbriquer les instructions if ?

Solution
Utilisez les oprateurs logiques ET (-a) et OU (-o) pour combiner plusieurs tests en une
seule expression. Par exemple :
if [ -r $FICHIER -a -w $FICHIER ]

Cette expression vrifie si le fichier peut tre lu et modifi.

Discussion
Toutes les conditions de test dun fichier incluent la vrification implicite de son existence. Il est donc inutile de vrifier si un fichier existe et sil peut tre lu. Sil nexiste pas,
il ne pourra pas tre lu.
Les conjonctions (-a pour ET et -o pour OU) peuvent tre employes avec toutes les
conditions de test. Elles ne sont pas limites aux caractristiques de fichiers.
Une mme instruction peut inclure plusieurs conjonctions et/ou. Vous devrez peut-tre
ajouter des parenthses pour fixer les priorits, comme dans a et (b ou c), mais
noubliez pas dannuler la signification particulire des parenthses en les faisant prcder dune barre oblique inverse ou en les plaant entre guillemets. Cependant, ne placez
pas lintgralit de lexpression entre des guillemets, car elle deviendrait alors un seul
terme trait comme un test de chane vide (voir la recette 6.5, page 123).
Voici un exemple de test plus complexe dans lequel les parenthses sont correctement
chappes :
if [ -r "$NF" -a \( -f "$NF" -o -p "$NF" \) ]

Lordre dvaluation de ces expressions nest pas le mme quen Java ou C. Dans ces langages, si la premire partie dune expression ET est fausse (ou vraie dans une expression
OU), la seconde partie nest pas value (lexpression est court-circuite). Cependant,
puisque le shell effectue plusieurs passes sur linstruction pendant la prparation de son
valuation (substitution des paramtres, etc.), les deux parties de la condition peuvent
tre partiellement values. Si dans cet exemple simple cela na pas dimportance, il nen
est pas de mme dans les cas plus compliqus. Par exemple :
if [ -z "$V1" -o -z "${V2:=ZUT}" ]

Mme si $V1 est vide, ce qui est suffisant pour ne pas avoir besoin dvaluer la deuxime
partie de la condition (vrifier si $V2 est vide) de linstruction if, il est possible que la
valeur de $V2 ait dj t modifie (comme effet secondaire de la substitution des paramtres pour $V2). Ltape de substitution des paramtres est effectue avant les tests -z.
Suivez-vous ? Que ce soit le cas ou non, sachez simplement que vous ne devez pas vous
appuyer sur des raccourcis dans vos conditions. Si vous avez besoin de ce genre de fonctionnement, dcomposez linstruction en deux if imbriques.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.5. Tester les caractristiques des chanes

123

Voir aussi

la recette 6.5, Tester les caractristiques des chanes, page 123 ;

lannexe C, Analyse de la ligne de commande, page 569, pour plus dinformations sur
le traitement de la ligne de commande.

6.5. Tester les caractristiques des chanes


Problme
Vous souhaitez que votre script vrifie la valeur de certaines chanes avant de les employer. Les chanes peuvent reprsenter lentre de lutilisateur, tre lues depuis un fichier ou tre des variables denvironnement passes au script.

Solution
La commande interne test permet deffectuer quelques tests simples, en utilisant le crochet dans les instructions if. Vous pouvez vrifier si une variable contient du texte et si
les valeurs (chanes) de deux variables sont gales.

Discussion
Par exemple :
#!/usr/bin/env bash
# bash Le livre de recettes : verifier_chaine
#
# instruction if
# Vrifie si la chane a une longueur.
#
# Utilise l'argument de la ligne de commande.
VAR="$1"
#
if [ "$VAR" ]
then
echo contient du texte
else
echo est vide
fi
#
if [ -z "$VAR" ]
then
echo est vide
else
echo contient du texte
fi

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

124

Chapitre 6 Logique et arithmtique

Lexpression a une longueur est dlibre. Deux types de variables peuvent ne pas
avoir de longueur : celles auxquelles une chane vide a t affecte et celles qui nont pas
reu de valeur. Ce test ne distingue pas ces deux cas. Il vrifie simplement que la variable
contient des caractres.
Les guillemets autour de lexpression "$VAR" sont importants car ils permettent dviter
que la syntaxe soit perturbe par lentre de lutilisateur. Si la valeur de $VAR est x -a 7
-lt 5 et si les guillemets ntaient pas utiliss, lexpression :
if [ -z $VAR ]

deviendrait alors (aprs la substitution de variable) :


if [ -z x -a 7 -lt 5 ]

Elle est tout fait valide, mais elle ne produit pas le rsultat attendu (vous ne savez pas
si la chane contient ou non des caractres).

Voir aussi

la recette 6.7, Tester avec des correspondances de motifs, page 126 ;

la recette 6.8, Tester avec des expressions rgulires, page 127 ;

la recette 14.2, viter lusurpation de linterprteur, page 294 ;

la section Oprateurs de test, page 536.

6.6. Tester lgalit


Problme
Vous souhaitez vrifier si deux variables du shell sont gales, mais il existe deux oprateurs de tests diffrents : -eq et = (ou ==). Lequel devez-vous choisir ?

Solution
Le type de la comparaison dtermine loprateur utiliser. Les comparaisons numriques se font avec loprateur -eq et les comparaisons de chanes avec = (ou ==).

Discussion
Voici un script simple qui illustre ce cas :
#!/usr/bin/env bash
# bash Le livre de recettes : chaine_ou_nombre
#
# Le bon vieux dilemme de la comparaison des chanes
# et des nombres.
#
VAR1=" 05 "
VAR2="5"

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.6. Tester lgalit

125

printf "%s" "sont-elles gales (avec -eq) ? "


if [ "$VAR1" -eq "$VAR2" ]
then
echo OUI
else
echo NON
fi
printf "%s" "sont-elles gales (avec =) ? "
if [ "$VAR1" = "$VAR2" ]
then
echo OUI
else
echo NON
fi

Lexcution du script produit la sortie suivante :


$ bash chaine_ou_nombre
sont-elles gales (avec -eq) ? OUI
sont-elles gales (avec =) ? NON
$

Alors que la valeur numrique des deux variables est la mme (5), des caractres, comme les zros de tte ou les espaces, peuvent faire que les chanes littrales sont diffrentes.
Les deux oprateurs = et == sont accepts, mais le premier est conforme au standard
Postfix et il est plus portable.
Pour vous aider dterminer la comparaison adapte, vous pouvez imaginer que loprateur -eq est similaire loprateur .eq. du langage FORTRAN. (FORTRAN est trs
orient calcul scientifique.) En ralit, il existe plusieurs oprateurs de comparaison
numrique, chacun est similaire un ancien oprateur de FORTRAN. Les abrviations,
donnes au tableau 6-3, sont suffisamment mnmoniques pour tre comprises (en anglais).
Tableau 6-3. Les oprateurs de comparaison de bash
Nombre

Chane

Signification

-lt

<

Infrieur .

-le

<=

Infrieur ou gal .

-gt

>

Suprieur .

-ge

>=

Suprieur ou gal .

-eq

=, ==

gal .

-ne

!=

Diffrent de.

Sachez quen Perl, ces oprateurs sont employs de manire oppose. Autrement dit, eq,
ne, etc. sont des oprateurs de comparaison de chanes, tandis que ==, !=, etc. sappliquent aux nombres.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

126

Chapitre 6 Logique et arithmtique

Voir aussi

la recette 6.7, Tester avec des correspondances de motifs, page 126 ;

la recette 6.8, Tester avec des expressions rgulires, page 127 ;

la recette 14.12, Valider lentre, page 308 ;

la section Oprateurs de test, page 536.

6.7. Tester avec des correspondances de motifs


Problme
Vous souhaitez tester une chane, non par rapport une constante littrale, mais par
rapport un motif. Par exemple, vous voulez savoir si le nom dun fichier correspond
un fichier JPEG.

Solution
Utilisez les doubles crochets dans une instruction if que les correspondances de motifs
du shell soient acceptes droite de loprateur gal :
if [[ "${NOM_FICHIER}" == *.jpg ]]

Discussion
Les doubles crochets sont une syntaxe rcente (bash version 2.01). Il ne sagit pas de lancienne version [ de la commande test, mais dun nouveau mcanisme de bash. Il utilise
les mmes oprateurs que le crochet simple, mais, dans ce cas, le signe gal est un comparateur de chane plus puissant. Cet oprateur peut tre constitu dun seul signe gal
ou dun double signe gal, comme nous lavons utilis dans lexemple prcdent. Leur
smantique est la mme. Nous prfrons employer le double signe gal (en particulier
avec la correspondance de motifs) pour souligner la diffrence, mais la correspondance
des motifs est apporte par les doubles crochets, non par le signe gal.
Dans la correspondance de motif classique, le caractre * correspond un nombre quelconque de caractres, le point dinterrogation (?) un seul caractre et les crochets indiquent la liste des caractres valides. Vous noterez quils ressemblent aux caractres
gnriques du shell et quils ne sont pas des expressions rgulires.
Ne placez pas le motif entre guillemets. Si la chane de notre exemple avait t entoure
de guillemets, la correspondance naurait trouv que les chanes dont le premier caractre est un astrisque.
Grce dautres options de bash, vous pouvez bnficier de possibilits de correspondances de motifs plus labores. tendons notre exemple afin de rechercher les noms
de fichiers qui se terminent par .jpg ou .jpeg :
shopt -s extglob
if [[ "$NN" == *.@(jpg|jpeg) ]]
then
# Traitement...

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.8. Tester avec des expressions rgulires

127

La commande shopt -s permet dactiver des options du shell. Loption extglob concerne la prise en charge de la correspondance de motifs tendue (ou globalisation). Dans ce
mode, nous pouvons dfinir plusieurs motifs, spars par le caractre | et regroups
dans des parenthses. Le premier caractre qui prcde les parenthses fixe le type de
correspondances avec les motifs. Dans notre exemple, le caractre @ stipule que la correspondance ne doit se faire quavec une seule occurence dun des motifs de la liste. Le
tableau 6-4 rsume les diffrentes possibilits (voir aussi la section Oprateurs pour la correspondance de motifs tendue extglob, page 547).
Tableau 6-4. Symboles de regroupement pour la correspondance de motif tendue
Regroupement

Signification

@( ... )

Une seule occurrence.

*( ... )

Aucune ou plusieurs occurrences.

+( ... )

Une ou plusieurs occurrences.

?( ... )

Aucune ou une occurrence.

!( ... )

Pas ces occurrences, mais tout le reste.

Les correspondances sont sensibles la casse, mais la commande shopt -s nocasematch


(dans bash versions 3.1+) permet de modifier ce fonctionnement. Cette option affecte
les commandes case et [[.

Voir aussi

la recette 14.2, viter lusurpation de linterprteur, page 294 ;

la recette 16.7, Adapter le comportement et lenvironnement du shell, page 386 ;

la section Options de shopt, page 517 ;

la section Caractres pour la correspondance de motifs, page 546 ;

la section Oprateurs pour la correspondance de motifs tendue extglob, page 547.

6.8. Tester avec des expressions rgulires


Problme
Parfois, mme la correspondance de motifs tendue active par loption extglob ne suffit pas. Il faut des expressions rgulires. Supposons que vous rcupriez le contenu dun
CD de musique classique dans un rpertoire et que la commande ls affiche les noms
suivants :
$ ls
Ludwig
Ludwig
Ludwig
Ludwig
Ludwig
$

[05/03/08]

bash Le livre de recettes

Van
Van
Van
Van
Van

Beethoven
Beethoven
Beethoven
Beethoven
Beethoven

01
02
03
04
05

Allegro.ogg
Adagio un poco mosso.ogg
Rondo - Allegro.ogg
"Coriolan" Overture, Op. 62.ogg
"Leonore" Overture, No. 2 Op. 72.ogg

Elodie FRITSCH <elodie.fritsch@total.com>

128

Chapitre 6 Logique et arithmtique

Vous souhaitez crire un script qui donne un nom plus simple ces fichiers, par exemple uniquement le numro du titre.

Solution
Utilisez la correspondance dexpression rgulire avec loprateur =~. Lorsquune chane
correspond, les diffrentes parties du motif sont disponibles dans la variable
$BASH_REMATCH. Voici la partie du script qui concerne la correspondance de motif :
#!/usr/bin/env bash
# bash Le livre de recettes : rechercher_titre
#
for PISTECD in *
do
if [[ "$PISTECD" =~ "([[:alpha:][:blank:]]*)- ([[:digit:]]*) - (.*)$" ]]
then
echo La piste ${BASH_REMATCH[2]} est le fichier ${BASH_REMATCH[3]}
mv "$PISTECD" "Piste${BASH_REMATCH[2]}"
fi
done
Ce script ncessite bash version 3.0 ou ultrieure car les versions plus
anciennes ne disposent pas de loprateur =~. Par ailleurs, bash version 3.2 a unifi la gestion des motifs dans les oprateurs de commande conditionnelle == et =~, mais a introduit un bogue subtil li
aux guillemets. Il a t corrig dans la version 3.2 patch #3. Si la solution donne prcdemment ne fonctionne pas, vous utilisez sans
doute bash version 3.2 sans le correctif. Vous pouvez passer une version plus rcente ou contourner le bogue en utilisant une version
moins lisible de lexpression rgulire. Elle consiste supprimer les
guillemets autour de lexpression rgulire et chapper toutes les
parenthses et tous les caractres espace :
if [[ "$PISTECD" =~ \([[:alpha:][:blank:]]*\)\ \([[:digit:]]*\)\ -\ \(.*\)\$ ]]

Discussion
Si vous avez lhabitude des expressions rgulires de sed, awk ou des anciens shells, vous
aurez certainement remarqu quelques lgres diffrences avec celles-ci. Les plus les videntes sont les classes de caractres, comme [:alpha:], et labsence dchappement sur
les parenthses de regroupement ; vous ncrivez pas \(, comme ce serait le cas dans sed.
Dans cette version des expressions rgulires, \( reprsente une parenthse littrale.
Les sous-expressions, chacune incluse entre des parenthses, servent remplir la variable tableau de bash, $BASH_REMATCH. Llment dindice zro, $BASH_REMATCH[0], contient lintgralit de la chane qui correspond lexpression rgulire. Les sousexpressions sont disponibles dans $BASH_REMATCH[1], $BASH_REMATCH[2], etc. Chaque
fois quune expression rgulire est employe de cette manire, elle remplit la variable
$BASH_REMATCH. Puisque dautres fonctions bash peuvent galement utiliser une correspondance dexpression rgulire, vous devez recopier cette variable le plus tt possible

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.8. Tester avec des expressions rgulires

129

afin de conserver ses valeurs pour une utilisation ultrieure. Dans notre exemple, puisque nous exploitons immdiatement les valeurs, dans la clause if/then, nous navons
pas besoin de les sauvegarder.
Les expressions rgulires ont souvent t dcrites comme des expressions en criture
seule, car elles sont trs difficiles dchiffrer. Nous allons construire pas pas celle de notre exemple afin de vous montrer comment nous lavons obtenu. Dans notre exemple,
les noms de fichiers ont le format gnral suivant :
Ludwig Van Beethoven - 04 - "Coriolan" Overture, Op. 62.ogg

Autrement dit, ils sont constitus, dans lordre, du nom du compositeur, du numro de
piste, du titre du morceau et de lextension .ogg (le CD a t converti au format Ogg
Vorbis, afin dobtenir des fichiers de petite taille, mais de haute fidlit).
Lexpression commence, gauche, par une parenthse ouvrante (gauche). Il sagit du dbut dune premire sous-expression. Nous y plaons une expression qui correspond la
premire partie du nom de fichier, cest--dire le nom du compositeur (lexpression est
signale en gras) :
([[:alpha:][:blank:]]*)- ([[:digit:]]*) - (.*)$

Le nom du compositeur est constitu dun nombre quelconque de caractres alphabtiques et despaces. Les crochets servent regrouper les caractres qui composent le
nom. Au lieu dcrire [A-Za-z0-9], nous utilisons les classes de caractres [:alpha:] et
[:blank:], en les plaant lintrieur des crochets. Nous ajoutons ensuite un astrisque
pour indiquer 0 ou plusieurs rptitions. La parenthse droite ferme la premire
sous-expression, qui est suivie dun tiret et dune espace.
La deuxime sous-expression (signale en gras) correspond au numro de piste :
([[:alpha:][:blank:]]*)- ([[:digit:]]*) - (.*)$

Elle commence par une autre parenthse gauche. Les numros de pistes sont des entiers,
constitus de chiffres (la classe de caractres [:digit:]). Nous indiquons ce format
lintrieur dune autre paire de crochets, suivie dun astrisque pour indiquer zro ou
plusieurs occurrences du contenu entre les crochets (cest--dire des chiffres). Notre
motif est ensuite compos dune espace, dun tiret et dune espace.
La dernire sous-expression collecte tous les caractres restants dans le nom du fichier,
y compris le nom du morceau et lextension de fichier :
([[:alpha:][:blank:]]*)- ([[:digit:]]*) - (.*)$

Cette troisime sous-expression (.*) est un grand classique des expressions rgulires.
Elle signifie nimporte quel nombre (*) de tout caractre (.). Nous terminons lexpression par un symbole dollar, qui correspond la fin de la chane. Les correspondances
sont sensibles la casse, mais la commande shopt -s nocasematch (disponible dans bash
versions 3.1+) permet de changer ce fonctionnement. Cette option affecte les commandes case et [[.

Voir aussi

man regex (Linux, Solaris, HP-UX, Mac) ou man re_format (BSD) pour tous les
dtails concernant votre bibliothque dexpressions rgulires ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

130

Chapitre 6 Logique et arithmtique

Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) ;

la recette 7.7, Utiliser des motifs plus complexes dans la recherche, page 157 ;

la recette 7.8, Rechercher un numro de scu, page 158 ;

la recette 19.15, Confondre caractres gnriques du shell et expressions rgulires, page


503.

6.9. Modifier le comportement avec des


redirections
Problme
Normalement, un script doit se comporter de la mme manire, que lentre provienne
du clavier ou dun fichier, ou que la sortie aille vers lcran ou un fichier. Cependant, il
arrive parfois que son fonctionnement doive tre diffrent selon ces critres de redirection. Comment pouvez-vous alors procder ?

Solution
Utilisez loption test -t dans une instruction if pour excuter du code diffrent en
fonctions des deux comportements souhaits.

Discussion
Rf lchissez deux fois avant demprunter cette voie. Une grande partie de la puissance
et de la souplesse des scripts bash vient du fait quils peuvent tre connects par des tubes. Vous devez avoir une trs bonne raison dimplmenter un comportement diffrent
lorsque lentre ou la sortie est dirige.

Voir aussi

la recette 2.18, Placer plusieurs redirections sur la mme ligne, page 50 ;

la recette 2.19, Enregistrer la sortie lorsque la redirection semble inoprante, page 51 ;

la recette 2.20, Permuter STDERR et STDOUT, page 53 ;

la recette 10.1, Convertir un script en dmon, page 207 ;

la recette 15.9, Utiliser la redirection du rseau de bash, page 348 ;

la recette 15.12, Rediriger la sortie pour toute la dure dun script, page 356 ;

la section Redirection des entres/sorties, page 537.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.10. Boucler avec while

131

6.10. Boucler avec while


Problme
Vous souhaitez que votre script effectue de manire rpte certaines actions, tant
quune certaine condition est satisfaite.

Solution
Utilisez une boucle while pour des conditions arithmtiques :
while (( COMPTEUR < MAX ))
do
raliser les actions
let COMPTEUR++
done

Pour des conditions lies au sywtme de fichiers :


while [ -z "$VERROU_FICHIER" ]
do
raliser les actions
done

Pour lire lentre :


while read ligneDeTexte
do
traiter $ligneDeTexte
done

Discussion
Les doubles parenthses dans la premire instruction while reprsentent des expressions arithmtiques, de manire trs similaire aux expressions $(( )) pour laffectation
dune variable du shell. Elles dlimitent une expression arithmtique et supposent que
les noms de variables mentionnes doivent tre drfrencs. Autrement dit, vous ne
devez pas crire $VAR mais VAR lintrieur des parenthses.
Les crochets dans while [ -z "$FICHIER_VERROU" ] ont la mme utilisation que dans
linstruction if ; le crochet unique quivaut linstruction test.
Le dernier exemple, while read ligneDeTexte, nutilise aucune parenthse, crochet ou
accolade. Dans bash, la syntaxe de linstruction while est dfinie de manire ce que la
condition soit une liste de commandes excuter (comme pour linstruction if) et
ltat de sortie de la dernire commande dtermine si la condition est vraie (0) ou fausse
(diffrent de 0).
Linstruction read retourne 0 lorsque la lecture russit et -1 en fin de fichier. Autrement
dit, la condition de while est vraie lorsque la lecture se passe bien, mais, lorsque la fin
du fichier est atteinte (-1 est retourn), elle devient fausse et la boucle se termine. ce
stade, linstruction excute est celle qui vient aprs done.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

132

Chapitre 6 Logique et arithmtique

Vous pourriez penser que la logique continuer boucler tout pendant que linstruction retourne zro est quelque peu inverse. La plupart des langages de type C emploient la logique oppose, cest--dire boucler tant que la valeur est diffrente de
zro . Mais, dans le shell, la valeur de retour zro signifie que tout sest bien pass, contrairement une valeur diffrente de zro qui indique une sortie en erreur.
Cela explique galement le fonctionnement de la construction (( )). Toute expression
lintrieur des parenthses est value et, si le rsultat est diffrent de zro, alors ltat
de sortie de (( )) est zro ; inversement, un rsultat gal zro retourne un. Nous pouvons donc crire des expressions comme le feraient les programmeurs Java ou C, mais
linstruction while respecte la logique de bash et sattend ce que zro signifie vrai.
Dun point de vue pratique, cela signifie que nous pouvons crire une boucle infinie de
la manire suivante :
while (( 1 ))
{
...
}

Elle convient parfaitement au programmeur C. Mais, noubliez pas que linstruction


while attend une valeur de retour gale zro, ce qui est le cas car (( )) retourne 0 pour
un rsultat vrai (cest--dire diffrent de zro).
Avant de quitter cette forme de boucle, revenons sur lexemple while read, qui lit depuis lentre standard (le clavier), et voyons comment le modifier pour lire lentre depuis un fichier.
Il existe trois manires de procder. La premire ne demande aucune modification de
linstruction. Elle consiste rediriger lentre standard vers un fichier au moment de
linvocation du script :
$ monScript <nom.fichier

Mais, supposons que vous ne vouliez pas laisser cette possibilit lappelant. Si vous savez quel fichier doit tre manipul ou sil a t fourni en argument votre script, vous
pouvez alors employer la mme boucle while, mais en redirigeant lentre vers le fichier :
while read ligneDeTexte
do
traiter la ligne
done < fichier.entree

Enfin, vous pouvez utiliser la commande cat pour envoyer le fichier sur la sortie standard et rediriger celle-ci vers lentre standard de linstruction while :
cat fichier.entree | \
while read ligneDeTexte
do
traiter la ligne
done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.11. Boucler avec read

133

cause du tube, la commande cat et la boucle while (y compris la partie traiter la ligne) sexcutent toutes deux dans des sous-shells distincts. Autrement dit, avec cette mthode, les commandes du script
dans la boucle while ne peuvent affecter les autres parties du script qui
se trouvent hors de la boucle. Par exemple, les variables dfinies
lintrieur de la boucle while nauront plus forcment ces valeurs une
fois la boucle termine. Ce nest pas le cas avec la solution while read
... done < fichier.entree, car il ne sagit pas dun tube.

Dans le dernier exemple, il ny a aucun caractre aprs la barre oblique inverse, juste un
saut de ligne. Par consquent, elle chappe le saut de ligne, indiquant au shell de continuer sur la ligne suivante sans terminer la ligne en cours. Il est ainsi plus facile de distinguer les deux actions (la commande cat et linstruction while).

Voir aussi

la recette 6.2, Conditionner lexcution du code, page 116 ;

la recette 6.3, Tester les caractristiques des fichiers, page 119 ;

la recette 6.4, Tester plusieurs caractristiques, page 122 ;

la recette 6.5, Tester les caractristiques des chanes, page 123 ;

la recette 6.6, Tester lgalit, page 124 ;

la recette 6.7, Tester avec des correspondances de motifs, page 126 ;

la recette 6.8, Tester avec des expressions rgulires, page 127 ;

la recette 6.11, Boucler avec read, page 133 ;

la recette 19.8, Oublier que les tubes crent des sous-shells, page 493.

6.11. Boucler avec read


Problme
quoi peut donc servir une boucle while ? Trs souvent, elle sert lire la sortie des
commandes prcdentes. Supposons que vous utilisiez le systme de gestion des versions Subversion, dont le programme excutable sappelle svn. (Un exemple avec cvs serait trs similaire.) Lorsque vous examinez une sous-arborescence pour savoir si des
fichiers ont t modifis, vous pouvez obtenir une sortie similaire la suivante :
$ svn status bcb
M
bcb/amin.c
?
bcb/dmin.c
?
bcb/mdiv.tmp
A
bcb/optrn.c
M
bcb/optson.c
?
bcb/prtbout.4161
?
bcb/rideaslist.odt
?
bcb/x.maxc
$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

134

Chapitre 6 Logique et arithmtique

Les lignes qui commencent par un point dinterrogation dsignent des fichiers inconnus de Subversion ; il sagit en loccurrence de fichiers de travail et de copies temporaires
de fichiers. Les lignes qui dbutent par A correspondent des fichiers nouvellement
ajouts. Celles qui commencent par M indiquent des fichiers modifis depuis la dernire
validation.
Nous voulons nettoyer le rpertoire en supprimant tous les fichiers de travail, cest-dire ceux qui se trouvent sur les lignes commenant par un point dinterrogation.

Solution
Essayez :
svn status mesSources | grep '^?' | cut -c8- | \
while read NF; do echo "$NF"; rm -rf "$NF"; done

Ou :
svn status mesSources | \
while read BALISE NF
do
if [[ $BALISE == \? ]]
then
echo $NF
rm -rf "$NF"
fi
done

Discussion
Les deux scripts permettent de supprimer les fichiers marqus dun point dinterrogation par svn.
La premire approche sappuie sur diffrents sous-programmes (ce nest pas vraiment
un problme aujourdhui avec la rapidit des processeurs) et tient normalement sur
une seule ligne dans une fentre de terminal classique. Elle utilise grep pour slectionner uniquement les lignes qui commencent (grce ^) par un point dinterrogation.
Lexpression '^?' est place entre apostrophes afin dannuler les significations particulires de ces caractres sous bash. Ensuite, la commande cut retient uniquement les caractres partir de la colonne huit et jusqu la fin de la ligne. Nous obtenons ainsi les
noms de fichiers que la boucle while doit traiter.
Linstruction read retourne une valeur diffrente de zro lorsque lentre est vide ; la
boucle se termine alors. Tant que lentre contient des donnes, read affecte la ligne de
texte lue la variable "$NF", qui correspond au fichier supprimer. Nous ajoutons les
options -rf pour le cas o le fichier inconnu serait en ralit un rpertoire de fichiers
et pour supprimer galement les fichiers en lecture seule. Si vous ne voulez pas une suppression aussi radicale, retirez ces options.
Le deuxime script est plus orient shell, car il na pas besoin de grep pour sa recherche,
qui sappuie sur linstruction if, ni de cut pour lanalyse, qui se fait avec une instruction
read. Nous lavons mis en forme comme devrait ltre un script dans un fichier. Si vous
le saisissez linvite de commande, vous pouvez retirer lindentation, mais nous prfrons une meilleure lisibilit lconomie de saisie.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.12. Boucler avec un compteur

135

Linstruction read dans ce deuxime script lit dans deux variables et non une seule. Cest
ainsi que nous demandons bash danalyser la ligne en deux lments (le caractre de
dbut et le nom de fichier). read convertit son entre en deux mots, comme des mots
sur la ligne de commande du shell. Le premier est affect la premire variable de la
liste donne dans linstruction read, le deuxime est affect la deuxime variable, etc.
La dernire variable de la liste reoit la fin de la ligne, mme si elle contient plusieurs
mots. Dans notre exemple, la valeur de $BALISE correspond au premier mot, qui est le
caractre (M, A ou ?) dont la fin est indique par lespace. Celle-ci dsigne galement le
dbut du mot suivant. La variable $NF prend le reste de la ligne, ce qui est important ici
car les noms de fichiers peuvent contenir des espaces ; nous ne voulons pas uniquement
le premier mot du nom de fichier. Le script supprime le fichier et la boucle reprend.

Voir aussi

lannexe D, Gestion de versions, page 575.

6.12. Boucler avec un compteur


Problme
Vous souhaitez excuter une boucle un nombre de fois dtermin. Vous pouvez employer une boucle while avec un dcomptage, mais les langages de programmation offrent les boucles for pour un tel idiome. Comment pouvez-vous le raliser avec bash ?

Solution
Utilisez un cas particulier de la syntaxe for, qui ressemble beaucoup au langage C, mais
avec des doubles parenthses :
$ for (( i=0 ; i < 10 ; i++ )) ; do echo $i ; done

Discussion
Dans les versions prcdentes du shell, la syntaxe de la boucle for ne permettait ditrer
que sur une liste fige dlments. Il sagissait dune grande innovation pour les langages
orients mot comme ceux des scripts shell, qui manipulent des noms de fichiers et
autres donnes analogues. Mais, lorsque les utilisateurs avaient besoin de compter, ils
crivaient parfois du code similaire au suivant :
for i in 1 2 3 4 5 6 7 8 9 10
do
echo $i
done

Si cela peut convenir aux petites boucles, il est assez difficile deffectuer 500 itrations.
(Imbriquer 5 10 boucles nest pas vraiment une solution !) En ralit, il faut une boucle for capable de compter.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

136

Chapitre 6 Logique et arithmtique

Cette boucle for spciale, avec une syntaxe de type C, est un ajout relativement rcent
bash (apparue dans la version 2.04). Voici sa forme la plus gnrale :
for (( expr1 ; expr2 ; expr3 )) ; do list ; done

Les doubles parenthses indiquent que les expressions sont arithmtiques. Vous navez
pas besoin dutiliser le symbole $ (comme dans $i, except pour les arguments comme
$1) dans les rfrences aux variables places lintrieur des doubles parenthses. Les
expressions sont des expressions arithmtiques entires qui offrent une grande varit
doprateurs, notamment la virgule pour inclure plusieurs oprations dans une mme
expression :
for (( i=0, j=0 ; i+j < 10 ; i++, j++ ))
do
echo $((i*j))
done

Cette boucle for initialise deux variables (i et j) et comporte une deuxime expression
plus complexe qui additionne les valeurs de ces variables avant de comparer le rsultat
une constante. Loprateur virgule est nouveau employ dans la troisime expression
pour incrmenter les deux variables.

Voir aussi

la recette 6.13, Boucler avec des valeurs en virgule flottante, page 136 ;

la recette 17.22, crire des squences, page 469.

6.13. Boucler avec des valeurs en virgule


flottante
Problme
Les expressions arithmtiques dune boucle for ne manipulent que des entiers. Comment utiliser des valeurs en virgule f lottante ?

Solution
Utilisez la commande seq pour gnrer la valeur en virgule f lottante (si elle existe sur
votre systme) :
for vf in $(seq 1.0 .01 1.1)
do
echo $vf; et autres actions
done

Ou :
seq 1.0 .01 1.1 | \
while read vf
do
echo $vf; et autres actions
done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.14. Raliser des branchements multiples

137

Discussion
La commande seq gnre une suite de nombres en virgule f lottante, un sur chaque ligne. Ses arguments correspondent la valeur de dpart, la valeur dincrment et la valeur de fin. Si vous tes habitu aux boucles for du langage C ou si vous vous tes initi
aux boucles avec le langage BASIC (par exemple, FOR I=4 TO 10 STEP 2), cet ordre des
arguments pourrait vous tonner. Avec la commande seq, lincrment se trouve au centre.
Dans le premier exemple, la construction $( ) excute la commande dans un sous-shell
et retourne le rsultat avec les sauts de ligne remplacs par une espace. Chaque valeur
est ainsi une chane pour la boucle for.
Dans le deuxime exemple, seq est excute comme une commande dont la sortie est
envoye par un tube dans une boucle while qui lit chaque ligne et effectue des actions.
Lorsque la suite des nombres est trs longue, vous devez opter pour cette approche car
la commande seq peut sexcuter en parallle de linstruction while. Dans la version base sur une boucle for, seq doit sexcuter entirement et placer lintgralit de sa sortie
sur la ligne de commande pour la passer linstruction for. Lorsque la suite de nombres
est trs longue, cette approche peut demander beaucoup de temps et de mmoire.

Voir aussi

la recette 6.12, Boucler avec un compteur, page 135 ;

la recette 17.22, crire des squences, page 469.

6.14. Raliser des branchements multiples


Problme
Vous devez effectuer tout un ensemble de comparaisons, mais la construction
if/then/else savre plutt longue et rptitive. Existe-t-il une meilleure solution ?

Solution
Utilisez linstruction case qui permet de dfinir plusieurs branchements :
case $NF in
*.gif) gif2png $NF
;;
*.png) pngOK $NF
;;
*.jpg) jpg2gif $NF
;;
*.tif | *.TIFF) tif2jpg $NF
;;
*) printf "Fichier non pris en charge : %s" $NF
;;
esac

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

138

Chapitre 6 Logique et arithmtique

Voici linstruction if/then/else quivalente :


if [[ $NF == *.gif ]]
then
gif2png $NF
elif [[ $NF == *.png ]]
then
pngOK $NF
elif [[ $NF == *.jpg ]]
then
jpg2gif $NF
elif [[ $NF == *.tif || $NF == *.TIFF ]]
then
tif2jpg $NF
else
printf "Fichier non pris en charge : %s" $NF
fi

Discussion
Linstruction case dveloppe le mot (avec substitution des paramtres) plac entre les
mots-cls case et in. Elle tente dtablir une correspondance entre ce mot et les motifs
indiqus. Cette fonctionnalit du shell est trs puissante. Elle neffectue pas simplement
une comparaison de valeurs, mais des correspondances de motifs. Notre exemple prsente des motifs simples : *.gif correspond toute suite de caractres (comme indiqu
par *) qui se termine par les caractres littraux .gif.
La barre verticale |, qui reprsente un OU logique, permet de sparer diffrents motifs
qui doivent mener la mme action. Dans notre exemple, si $NF se termine par .tif
ou par .TIFF, la correspondance de motifs existe alors et la commande tif2jpg (fictive)
est excute.
Les doubles points-virgules terminent lensemble dinstructions excutes en cas de correspondance.
Il nexiste aucun mot-cl else ou default pour prciser les instructions excuter lorsquaucun motif ne correspond. la place, utilisez * comme dernier motif, puisquil correspond nimporte quelle chane. En le plaant la fin, il joue le rle de clause par
dfaut et correspond tout ce qui na pas encore trouv de correspondance.
Les programmeurs C/C++ et Java auront remarqu que linstruction case de bash est similaire linstruction switch de leur langage et que chaque motif correspond un cas.
Cependant, il est important de noter que la variable de case est une variable du shell
(en gnral une chane) et que les cas sont des motifs (non des valeurs constantes). Les
motifs se terminent par une parenthse droite ( la place des deux-points). Lquivalent
au break des instructions switch de C/C++ et Java est, en bash, un double point-virgule.
Lquivalent du mot-cl default est, en bash, le motif *.
Les correspondances sont sensibles la casse, mais vous pouvez changer ce fonctionnement laide de la commande shopt -s nocasematch (disponible dans bash versions
3.1+). Cette option affecte les commandes case et [[.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.15. Analyser les arguments de la ligne de commande

139

Linstruction case se termine par esac (cest--dire case pel lenvers ; endcase
tait sans doute trop long, un peu comme elif, la place de elseif , qui est plus concis).

Voir aussi

help case ;

help shopt ;

la recette 6.2, Conditionner lexcution du code, page 116.

6.15. Analyser les arguments de la ligne de


commande
Problme
Vous souhaitez crire un script shell simple pour afficher une ligne de tirets. Mais, vous
voulez que des paramtres prcisent la longueur de la ligne et le caractre employer
la place du tiret, si ncessaire. La syntaxe doit tre la suivante :
tirets
tirets 50
tirets -c= 50
tirets -cx

#
#
#
#

Affiche
Affiche
Affiche
Affiche

72
50
50
72

tirets.
tirets.
signes gal.
caractres x.

Quel est la faon la plus simple danalyser ces arguments ?

Solution
Pour des scripts professionnels, vous devez utiliser la commande interne getopts. Mais,
nous souhaitons vous montrer linstruction case en action. Par consquent, dans ce cas
simple, lanalyse des arguments se fera avec case.
Voici le dbut du script (voir la recette 12.1, page 239, pour une version complte) :
#!/usr/bin/env bash
# bash Le livre de recettes : tirets
#
# tirets - affiche une ligne de tirets
#
# options : # longueur de la ligne (72 par dfaut)
#
-c X utiliser le caractre X la place du tiret
#
LONGUEUR=72
CARACTERE='-'
while (( $# > 0 ))
do
case $1 in

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

140

Chapitre 6 Logique et arithmtique

[0-9]*) LONGUEUR=$1
;;
-c) shift;
CARACTERE=${1:--}
;;
*) printf 'usage : %s [-c X] [#]\n' $(basename $0) >&2
exit 2
;;
esac
shift
done
#
# suite...

Discussion
La longueur (72) et le caractre (-) par dfaut sont fixs au dbut du script (aprs quelques commentaires utiles). La boucle while nous permet danalyser plusieurs paramtres. Elle se poursuit tant que le nombre darguments ($#) est suprieur zro.
Linstruction case recherche les correspondances avec trois motifs diffrents. Premirement, [0-9]* correspond un chiffre suivi de nimporte quel caractre. Nous aurions
pu utiliser une expression plus labore pour naccepter que des nombres, mais nous
supposerons que tout argument qui commence par un chiffre est un nombre. Si ce nest
pas le cas, par exemple si lutilisateur a saisi 1T4, le script affiche une erreur lorsquil tente demployer la variable $LONGUEUR. Pour le moment, nous ferons avec.
Le deuxime motif est la chane littrale -c, qui demande une correspondance exacte.
Lorsquelle est trouve, nous utilisons la commande interne shift pour carter cet argument, nous prenons ensuite le suivant (qui est prsent le premier argument, cest-dire $1) et nous enregistrons le nouveau choix de caractre. La rfrence $1 utilise
loprateur :- (cest--dire, ${1:-x}) pour donner une valeur par dfaut si le paramtre
nest pas fix. De cette manire, si lutilisateur saisit -c mais oublie de prciser le caractre, la valeur par dfaut, indique juste aprs loprateur :-, est choisie. Dans lexpression ${1:-x}, cette valeur par dfaut est x. Dans notre script, nous avons crit ${1:--}
(remarquez les deux signes moins) et le caractre par dfaut est donc le (deuxime) signe moins.
Le troisime motif (*) correspond toute chane de caractres. Par consquent, les arguments qui nont pas trouv de correspondance avec les motifs prcdents seront traits par ce cas. En le plaant la fin de linstruction case, il permet de prendre en charge
tous les cas invalides et dafficher un message derreur lutilisateur (puisque les paramtres ne sont pas corrects).
Si vous dbutez avec bash, le message derreur affich par printf mrite sans doute quelques explications. Vous devez examiner quatre parties de cette instruction. La premire
est simplement constitue du nom de la commande, printf. La deuxime reprsente la
chane de format employe par printf (voir la recette 2.3, page 34, et la section printf,
page 540). Nous plaons la chane entre apostrophes afin que le shell ne tente pas de
linterprter. La dernire partie de la ligne (>&2) demande au shell de rediriger la sortie
vers lerreur standard (puisquil sagit dun message derreur). Les dveloppeurs de

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.15. Analyser les arguments de la ligne de commande

141

scripts ne prtent pas toujours attention ce point et omettent souvent cette redirection
des messages derreur. Nous pensons quil est prfrable de prendre lhabitude de toujours rediriger les messages derreur vers lerreur standard.
La troisime partie de la ligne invoque un sous-shell pour excuter la commande basename avec $0 en argument et placer la sortie sous forme dun texte sur la ligne de commande. Cet idiome classique est souvent employ pour retirer le chemin qui se trouve
au dbut de la commande invoque. Par exemple, examinons ce qui se passe si nous utilisions uniquement $0. Voici deux invocations du mme script. Examinez les messages
derreur :
$ tirets -g
usage : tirets [-c X] [#]
$ /usr/local/bin/tirets -g
usage : /usr/local/bin/tirets [-c X] [#]

La seconde invocation prcise le nom de chemin complet. Le message derreur contient


donc galement ce nom de chemin complet. Pour viter dafficher cette information,
nous extrayons de $0 uniquement le nom de base du script, laide de la commande
basename. Les messages derreur sont alors les mmes, quelle que soit la manire dont
le script est invoqu :
$ tirets -g
usage : tirets [-c X] [#]
$ /usr/local/bin/tirets -g
usage : tirets [-c X] [#]

Mme si cela est un peu plus long que de figer le nom du script dans le code ou demployer directement $0, ce temps dexcution supplmentaire nest pas important car il
sagit dun message derreur et le script va sarrter.
Nous terminons linstruction case par esac et invoquons nouveau shift pour retirer
largument qui vient dtre trait par linstruction case. Si nous ne procdions pas ainsi,
la boucle while analyserait indfiniment le mme argument. Linstruction shift dplace le deuxime argument ($2) en premire position ($1), le troisime en deuxime position, etc. De plus, la variable $# est chaque fois dcrmente de un. Aprs quelques
itrations, $# atteint finalement la valeur zro (lorsquil ny a plus darguments) et la
boucle se termine.
Laffichage des tirets (ou dun autre caractre) nest pas prsent dans cet exemple, car
nous voulions nous concentrer sur linstruction case. Le script complet, avec une fonction daffichage du message dutilisation, est donn la recette 12.1, page 239.

Voir aussi

help case ;

help getopts ;

help getopt ;

la recette 2.3, Mettre en forme la sortie, page 34 ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

142

Chapitre 6 Logique et arithmtique

la recette 5.8, Parcourir les arguments dun script, page 96 ;

la recette 5.11, Compter les arguments, page 101 ;

la recette 5.12, Extraire certains arguments, page 103 ;

la recette 12.1, Afficher une ligne de tirets, page 239 ;

la recette 13.1, Analyser les arguments dun script, page 257 ;

la recette 13.2, Afficher ses propres messages derreur lors de lanalyse, page 260 ;

la section printf, page 540.

6.16. Crer des menus simples


Problme
Vous avez un script SQL simple que vous aimeriez excuter pour diffrentes bases de
donnes. Vous pourriez donner le nom de la base de donnes sur la ligne de commande,
mais vous souhaitez un fonctionnement plus interactif, en choisissant la base de donnes dans une liste de noms.

Solution
Utilisez linstruction select pour crer des menus textuels simples. Voici un exemple :
#!/usr/bin/env bash
# bash Le livre de recettes : init_bd.1
#
LISTE_BD=$(sh ./listebd | tail +2)
select BD in $LISTE_BD
do
echo Initialisation de la base de donnes : $BD
mysql -uuser -p $BD <monInit.sql
done

Pour le moment, ne vous proccupez pas de savoir comment $LISTE_BD obtient ses valeurs. Sachez simplement quil sagit dune liste de mots (similaire la sortie dune commande ls). Linstruction select affiche ces mots, chacun prcd dun numro, et une
invite pour lutilisateur. Celui-ci fait son choix en saisissant le numro. Le mot correspondant est alors affect la variable prcise aprs le mot-cl select (dans ce cas BD).
Voici un exemple dexcution de ce script :
$ ./init_bd
1) testBD
2) inventaireSimple
3) inventairePrincipal
4) autreBD
#? 2
Initialisation de la base de donnes : inventaireSimple
#?
$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.17. Modifier linvite des menus simples

143

Discussion
Lorsque lutilisateur tape 2 , le mot inventaireSimple est affect la variable BD. Si
vous voulez obtenir le numro choisi par lutilisateur, vous le trouverez dans la variable
$REPLY.
Linstruction select est en ralit une boucle. Lorsque vous avez fait un choix, le corps
de la boucle (entre do et done) est excut, puis vous revenez linvite afin dindiquer
une nouvelle valeur.
La liste nest pas raffiche chaque fois, mais uniquement si vous nindiquez aucun numro et appuyez simplement sur la touche Entre. Par consquent, si vous souhaitez revoir la liste, appuyez directement sur Entre.
Le code plac aprs in nest pas rvalu. Autrement dit, la liste ne peut pas tre modifie une fois linstruction select excute. Si vous changez la valeur de $LISTE_BD lintrieur de la boucle, cela ne modifie en rien la liste des options du menu.
La boucle sarrte lorsquelle atteint la fin du fichier, qui, dans une utilisation interactive, est reprsente par Ctrl-D. Si vous envoyez, via un tube, un ensemble de choix une
boucle select, celle-ci se termine la fin de lentre.
Vous navez pas la possibilit de mettre en forme la liste. Vous devez vous contenter de
laffichage produit par linstruction select. En revanche, vous pouvez modifier linvite.

Voir aussi

la recette 3.7, Choisir dans une liste doptions, page 68 ;

la recette 16.2, Personnaliser linvite, page 368 ;

la recette 16.10, Utiliser les invites secondaires : $PS2, $PS3 et $PS4, page 390.

6.17. Modifier linvite des menus simples


Problme
Vous naimez pas linvite par dfaut des menus de select et vous souhaitez donc la
changer.

Solution
La variable denvironnement $PS3 de bash contient linvite affiche par select. En modifiant cette variable, vous obtenez une nouvelle invite.

Discussion
Il sagit de la troisime invite de bash. La premire ($PS1) correspond celle affiche
avant la plupart des commandes. (Nous avons utilis $ dans nos exemples, mais elle
peut tre beaucoup plus labore et inclure, par exemple, un identifiant dutilisateur et
des noms de rpertoires.) Si une commande est trs longue et se poursuit sur la ligne
suivante, la deuxime invite ($PS2) est prsente.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

144

Chapitre 6 Logique et arithmtique

Les boucles select affichent la troisime invite ($PS3). Vous devez lui donner la valeur
souhaite avant linstruction select. Vous pouvez mme la modifier lintrieur de la
boucle pour la faire voluer en fonction du droulement du code.
Voici un script, similaire celui de la recette prcdente, qui compte le nombre dentres valides traites :
#!/usr/bin/env bash
# bash Le livre de recettes : init_bd.2
#
LISTE_BD=$(sh ./listebd | tail +2)
PS3="0 initialisations >"
select BD in $LISTE_BD
do
if [ $BD ]
then
echo Initialisation de la base de donnes : $BD
PS3="$((i++)) initialisations >"
mysql -uuser -p $BD <monInit.sql
fi
done
$

Nous avons ajout quelques espaces pour que le contenu de $PS3 soit plus clair. Linstruction if nous permet de comptabiliser uniquement les choix valides de lutilisateur.
Cette vrification serait galement utile dans la version prcdente, mais nous lavions
voulue simple.

Voir aussi

la recette 3.7, Choisir dans une liste doptions, page 68 ;

la recette 6.17, Modifier linvite des menus simples, page 143 ;

la recette 16.2, Personnaliser linvite, page 368 ;

la recette 16.10, Utiliser les invites secondaires : $PS2, $PS3 et $PS4, page 390.

6.18. Crer une calculatrice NPI simple


Problme
Vous tes sans doute capable de convertir mentalement des valeurs binaires en dcimal,
octal ou hexadcimal, mais vous ne parvenez plus effectuer des oprations arithmtiques simples et vous ne trouvez aucune calculatrice.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.18. Crer une calculatrice NPI simple

145

Solution
Crez votre propre calculatrice en utilisant larithmtique du shell et la notation polonaise inverse (NPI) :
#!/usr/bin/env bash
# bash Le livre de recettes : calc_npi
#
# Calculatrice NPI simple (entire) en ligne de commande.
#
# Prend les arguments et effectue le calcul donn sous la forme
# a b op.
# Accepte le caractre x la place de *.
#
# Vrification du nombre d'arguments :
if [ \( $# -lt 3 \) -o \( $(($# % 2)) -eq 0 \) ]
then
echo "usage : calc_npi nombre nombre oprateur [ nombre oprateur ] ..."
echo "utiliser x ou '*' pour la multiplication"
exit 1
fi
RESULTAT=$(($1 ${3//x/*} $2))
shift 3
while [ $# -gt 0 ]
do
RESULTAT=$((RESULTAT ${2//x/*} $1))
shift 2
done
echo $RESULTAT

Discussion
$(( )) effectue uniquement une arithmtique entire.

Lcriture NPI (ou postfixe) place les oprandes (les nombres) en premier, puis loprateur. Dans cette notation, nous ncrivons pas 5 + 4, mais 5 4 +. Si nous voulons multiplier le rsultat par 2, il suffit dajouter 2 * la fin. Lexpression globale est alors 5 4 + 2
*. Elle est parfaitement adapte un traitement informatique car le programme peut
lire de gauche droite sans jamais avoir besoin de parenthses. Le rsultat de toute opration devient le premier oprande de lexpression suivante.
Dans notre calculatrice bash simple, nous acceptons que le caractre x soit utilis la place du symbole de multiplication, car * a une signification spciale pour le shell. Mais, si
vous lui appliquez lchappement, en crivant '*' ou \*, cela fonctionne galement.
Quels sont les contrles de validit des arguments ? Nous considrons quil faut au
moins trois arguments (deux oprandes et un oprateur, par exemple 6 3 /). Il est pos[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

146

Chapitre 6 Logique et arithmtique

sible davoir plus de trois arguments, mais, dans ce cas, leur nombre doit tre impair ;
cest--dire au moins trois plus une ou plusieurs occurences de deux autres arguments
(un deuxime oprande et loprateur suivant). Par consquent, le nombre darguments valides est 3 ou 5 ou 7 ou 9, etc. Nous vrifions ce point avec lexpression suivante, dont la valeur de retour doit tre gale 0 :
$(($# % 2)) -eq 0

La construction $(( )) indique une opration arithmtique. Loprateur % (appel reste)


nous permet de savoir si le reste de la division de $# (le nombre darguments) par 2 est
gal 0 (-eq 0).
Une fois le nombre darguments valid, nous pouvons les employer dans le calcul du
rsultat :
RESULTAT=$(($1 ${3//x/*} $2))

Cette expression calcule le rsultat et remplace en mme temps le caractre x par *. Lorsque vous invoquez le script, vous lui passez une expression NPI sur la ligne de commande, mais larithmtique effectue par le shell utilise une notation classique (infixe). Il est
donc possible dvaluer lexpression lintrieur de $(( )), mais il faut rordonner les
arguments. En ignorant la substitution x en *, pour le moment, nous avons :
RESULTAT=$(($1 $3 $2))

Loprateur est simplement dplac entre les deux oprandes. bash effectue la substitution des paramtres avant de procder aux calculs arithmtiques. Si $1 vaut 5, $2 vaut 4
et $3 est le signe +, nous obtenons alors lexpression suivante aprs la substitution les
paramtres :
RESULTAT=$((5 + 4))

bash value lexpression et affecte la valeur obtenue, 9, RESULTAT. prsent que nous
en avons termin avec ces trois arguments, linstruction shift 3 permet de les retirer et
de laisser la place aux prochains. Puisque nous avons dj vrifi que le nombre darguments tait impair, nous savons quil en reste au moins deux (ou aucun). Sil nen restait
quun, leur nombre serait pair (3+1=4).
partir de l, nous entrons dans une boucle qui traite deux arguments la fois. Le rsultat prcdent devient le premier oprande, largument suivant ($1 suite au dcalage)
constitue le deuxime oprande et loprateur, donn par $2, entre les deux oprandes.
Lvaluation de lexpression se fait comme prcdemment. Lorsquil ny a plus darguments, le rsultat du calcul se trouve dans RESULTAT.
Revenons la substitution. ${2} fait rfrence au deuxime argument. Cependant, nous
omettons souvent {} pour crire simplement $2. Mais, dans ce cas, nous en avons besoin
car nous demandons bash deffectuer dautres oprations sur largument. Lexpression
${2//x/*} utilise indique que nous voulons remplacer (//) un caractre x par (indiqu
par le caractre / suivant) * avant de retourner la valeur de $2. Nous aurions pu crire
cette opration en deux tapes en impliquant une autre variable :
OP=${2//x/*}
RESULTAT=$((RESULTAT OP $1))

Cette variable supplmentaire pourrait vous tre utile dans vos premires utilisations
de ces fonctionnalits de bash. Mais, une fois que ces expressions courantes vous seront

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

6.19. Crer une calculatrice en ligne de commande

147

devenues familires, vous les crirez automatiquement sur une seule ligne (bien quelles
soient alors moins faciles lire).
Vous vous demandez peut-tre pourquoi nous navons pas crit $RESULTAT et $OP dans
lexpression qui ralise lvaluation. Nous navons pas besoin dutiliser le symbole $ avec
les noms de variables placs lintrieur des expressions $(( )), lexception des paramtres positionnels (par exemple, $1, $2). En effet, ceux-ci doivent tre diffrencis des
nombres littraux (par exemple, 1, 2).

Voir aussi

le chapitre 5, Variables du shell, page 85 ;

la recette 6.19, Crer une calculatrice en ligne de commande, page 147.

6.19. Crer une calculatrice en ligne de


commande
Problme
Larithmtique entire ne nous suffit plus et lcriture NPI ne vous a jamais vraiment
passionn. Vous souhaitez donc une approche diffrente pour une calculatrice en ligne
de commande.

Solution
Crez une calculatrice triviale qui utilise les expressions arithmtiques en virgule f lottante de la commande awk :
# bash Le livre de recettes : fonction_calculer
# Calculatrice en ligne de commande triviale.
function calculer
{
awk "BEGIN {print \"La rponse est : \" $* }";
}

Discussion
Vous pourriez tre tent dcrire echo La rponse est : $(( $* )), qui fonctionne parfaitement avec les entiers, mais qui tronquera le rsultat des oprations en virgule f lottante.
Nous avons crit une fonction car les alias nautorisent pas lemploi des arguments.
Vous la placerez probablement dans votre fichier global /etc/bashrc ou dans votre fichier
local ~/.bashrc.
Les oprateurs nont rien de mystrieux et sont les mmes quen C :
$ calc 2 + 3 + 4

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

148

Chapitre 6 Logique et arithmtique

La rponse est : 9
$ calc 2 + 3 + 4.5
La rponse est : 9.5

Faites attention aux caractres interprts par le shell. Par exemple :


$ calc (2+2-3)*4
-bash: syntax error near unexpected token `2+2-3'

Vous devez annuler la signification particulire des parenthses. Vous avez le choix entre placer lexpression entre apostrophes ou ajouter une barre oblique inverse devant
chaque caractre spcial (pour le shell). Par exemple :
$ calc '(2+2-3)*4'
La rponse est : 4
$ calc \(2+2-3\)\*4
La rponse est : 4
$ calc '(2+2-3)*4.5'
La rponse est : 4.5

Le symbole de multiplication doit galement tre chapp, puisquil sagit dun caractre gnrique pour les noms de fichiers. Cest notamment le cas lorsque vous placez des
espaces autour des oprateurs, comme dans 17 + 3 * 21, car * correspond alors tous les
fichiers du rpertoire de travail. Cette liste de noms est insre sur la ligne de commande
la place de lastrisque. Il est alors difficile dobtenir le rsultat attendu.

Voir aussi

man awk ;

la section VALUATION ARITHMTIQUE de la page de manuel de bash ;

la recette 6.18, Crer une calculatrice NPI simple, page 144 ;

la recette 16.6, Raccourcir ou modifier des noms de commandes, page 385.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7
Outils shell intermdiaires I

Il est temps prsent dtendre notre rpertoire. Les recettes de ce chapitre sappuient
sur des utilitaires qui ne font pas partie du shell, mais leur intrt est indniable et il est
difficile dimaginer le shell sans eux.
La philosophie dUnix (et donc de Linux) est demployer de petits programmes ( la porte limite) et de les runir pour obtenir des rsultats plus grands. la place dun seul
programme qui fait tout, nous avons de nombreux programmes diffrents qui ralisent
chacun une seule tche.
Cest galement lapproche de bash. Bien que ses possibilits soient de plus en plus nombreuses, il ne tente pas de tout accomplir. Il est parfois plus simple dutiliser des commandes externes pour raliser une tche, mme si bash pourrait y parvenir en faisant
un effort.
Prenons un exemple simple bas sur la commande ls. Vous navez pas besoin de cette
commande pour obtenir le contenu de votre rpertoire courant. La commande echo *
affiche tous les noms de fichiers. Vous pouvez mme tre plus fantaisiste, en utilisant la
commande printf de bash et une mise en forme adapte. Mais ce nest pas rellement
lobjectif dun interprteur de commandes et il existe dj un programme (ls) qui prend
en charge les diverses informations du systme de fichiers.
Mais le plus important est peut-tre quen ne demandant pas bash doffrir toutes les
possibilits daffichage du contenu dun systme de fichiers, nous lui autorisons une certaine indpendance dvolution. De nouvelles versions de ls peuvent tre dveloppes
sans que tous les utilisateurs mettent niveau leur interprteur de commandes.
Assez de philosophie, revenons la pratique.
Dans ce chapitre, nous nous intressons aux trois principaux utilitaires de manipulation
de texte : grep, sed et awk.
grep recherche des chanes, sed offre un mcanisme de modification du texte au travers
dun tube et awk est assez remarquable, car il sagit un prcurseur de perl et une sorte
de camlon (il peut tre assez diffrent en fonction de son utilisation).
Ces utilitaires, ainsi que quelques autres que nous tudierons dans le chapitre suivant,
sont employs par la plupart des scripts shell et la majorit des sessions de commandes
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

150

Chapitre 7 Outils shell intermdiaires I

avec le shell. Si votre script travaille sur une liste de fichiers, il est fort probable que find
ou grep fournira cette liste et que sed et/ou awk analysera lentre ou mettra en forme la
sortie quelque part dans le script.
Autrement dit, si nos exemples de scripts doivent sattaquer des problmes rels, ils
doivent sappuyer sur la diversit doutils emloyes par les utilisateurs et programmeurs
bash.

7.1. Rechercher une chane dans des fichiers


Problme
Vous souhaitez trouver toutes les occurrences dune chane dans un ou plusieurs fichiers.

Solution
La commande grep examine les fichiers la recherche de lexpression indique :
$ grep printf *.c
both.c:
printf("Std Out message.\n", argv[0], argc-1);
both.c:
fprintf(stderr, "Std Error message.\n", argv[0], argc-1);
good.c:
printf("%s: %d args.\n", argv[0], argc-1);
somio.c:
// we'll use printf to tell us what we
somio.c:
printf("open: fd=%d\n", iod[i]);
$

Les fichiers analyss dans cet exemple se trouvent tous dans le rpertoire de travail.
Nous avons employ le motif simple *.c pour trouver tous les fichiers dont le nom se
termine par .c, sans nom de chemin.
Cependant, les fichiers examiner ne se trouveront sans doute pas dans un endroit aussi
pratique. Dans ce cas, utilisez des noms de chemins. Par exemple :
$ grep printf ../lib/*.c ../server/*.c ../cmd/*.c */*.c

Discussion
Lorsque grep traite un fichier, il commence par afficher son nom, suivi dun caractre
deux-points. Le texte ajout aprs ces deux-points reprsente ce que grep a trouv dans
le fichier.
La recherche retourne toutes les occurrences des caractres. La ligne qui contient la chane fprintf a t affiche car printf est inclus dans fprintf .
Le premier argument (autre quune option) de grep peut tre une simple chane, comme dans cet exemple, ou une expression rgulire plus complexe. Ces expressions rgulires sont diffrentes de celles employes pour la correspondance de motifs dans le
shell, mme si elles semblent parfois similaires. La correspondance de motifs est si puissante que vous risquez de ne plus pouvoir vous en passer.
Les options de grep permettent de varier la sortie gnre. Si laffichage des noms de fichiers vous gne, dsactivez cette fonctionnalit laide de loption -h :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.2. Garder uniquement les noms de fichiers

151

$ grep -h printf *.c


printf("Std Out message.\n", argv[0], argc-1);
fprintf(stderr, "Std Error message.\n", argv[0], argc-1);
printf("%s: %d args.\n", argv[0], argc-1);
// we'll use printf to tell us what we
printf("open: fd=%d\n", iod[i]);
$

Si les lignes du fichier ne vous intressent pas et que seul le nombre doccurrences de
lexpression est important, utilisez alors loption -c :
$ grep -c printf *.c
both.c:2
good.c:1
somio.c:2
$
Lerreur classique est doublier de donner une entre grep. Par exemple, grep maVar. Dans ce cas, grep suppose que lentre provient de
STDIN, alors que vous pensez quelle correspond un fichier. La commande grep attend donc patiemment et semble ne rien faire. En ralit, elle attend votre entre depuis le clavier. Cette erreur est assez difficile constater lorsque la recherche se fait dans une grande quantit
de donnes et prend donc du temps.

Voir aussi

man grep ;

man regex (Linux, Solaris, HP-UX) ou man re_format (BSD, Mac) pour tous les
dtails concernant votre bibliothque dexpressions rgulires ;

Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) ;

Introduction aux scripts shell de Nelson H.F. Beebe et Arnold Robbins (ditions
OReilly), chapitre 3 ;

le chapitre 9, Rechercher des fichiers avec find, locate et slocate, page 191 et lutilitaire
find, pour dautres formes de recherche ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490.

7.2. Garder uniquement les noms de fichiers


Problme
Vous souhaitez trouver les fichiers qui contiennent une certaine chane. La ligne qui
contient le texte ne vous intresse pas, seuls les noms des fichiers sont importants.

Solution
Utilisez loption -l de grep pour ne garder que les noms de fichiers :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

152

Chapitre 7 Outils shell intermdiaires I

$ grep -l printf *.c


both.c
good.c
somio.c

Discussion
Si grep trouve plusieurs correspondances dans un mme fichier, le nom nest affich
quune seule fois. Si aucune correspondance nest trouve, le nom nest pas prsent.
Cette option est trs pratique lorsque vous souhaitez construire une liste de fichiers sur
lesquels travailler ensuite. Placez la commande grep dans une construction $( ) et les
noms de fichiers qui vous intressent peuvent alors tre ajouts la ligne de commande.
Par exemple, voici une commande qui permet de supprimer les fichiers qui contiennent
la phrase Ce fichier est obsolte :
$ rm -i $(grep -l 'Ce fichier est obsolte' * )

Nous avons ajout loption -i rm, afin que vous validiez chaque suppression de fichiers. tant donn le potentiel de cette combinaison de commande, cette prcaution
nest pas superf lue.
bash tend * afin de correspondre tous les fichiers du rpertoire de travail (mais sans
aller dans les sous-rpertoires) et passe la liste obtenue en argument grep. Celui-ci produit ensuite la liste des noms de fichiers qui contiennent la chane indique. Enfin, cette
liste est reue par la commande rm, qui supprime chaque chaque fichier.

Voir aussi

man grep ;

man rm ;

man regex (Linux, Solaris, HP-UX) ou man re_format (BSD, Mac) pour tous les
dtails concernant votre bibliothque dexpressions rgulires ;

Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) ;

la recette 2.15, Relier une sortie une entre, page 46 ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490.

7.3. Obtenir une rponse vrai/faux partir


dune recherche
Problme
Vous souhaitez savoir si une chane se trouve dans un certain fichier, mais le contenu
ne nous intresse pas, uniquement une rponse de type oui ou non.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.3. Obtenir une rponse vrai/faux partir dune recherche

153

Solution
Utilisez -q, loption tranquillit de grep. Pour une portabilit maximum, vous pouvez galement rediriger la sortie vers /dev/null. Dans les deux cas, la rponse se trouve
dans la variable dtat de sortie $?. Vous pouvez donc vous en servir dans un test if :
$ grep -q chaine fichier.volumineux
$ if [ $? -eq 0 ] ; then echo oui ; else echo non ; fi
non
$

Discussion
Dans un script shell, laffichage sur lcran des rsultats de la recherche nest pas toujours
souhait. Vous voulez simplement savoir si une correspondance a t trouve afin que
votre script prenne les bonnes dcisions.
Comme pour la plupart des commandes Unix/Linux, le code de retour 0 indique un
bon droulement. Dans ce cas, la commande a russi si elle a trouv la chane dans au
moins lun des fichiers indiqus (dans cet exemple, la recherche se fait dans un seul fichier). La valeur de retour est stocke dans la variable $? du shell, que nous plaons dans
une instruction if.
Si nous donnons plusieurs noms de fichiers aprs grep -q, grep sarrte ds que la premire concurrence de la chane est trouve. Il ne traite pas tous les fichiers, car vous souhaitez uniquement savoir sil a trouv ou non une occurrence de la chane. Si vous
voulez vraiment examiner tous les fichiers, la place de -q, utilisez la solution suivante :
$ grep chaine fichier.volumineux >/dev/null
$ if [ $? -eq 0 ] ; then echo oui ; else echo non ; fi
non
$

La redirection vers /dev/null envoie la sortie vers un priphrique particulier, une benne
bits, qui jette tout ce que vous lui donnez.
La technique /dev/null savre galement utile pour crire des scripts shell portables avec
les diffrentes variantes de grep disponibles sur les systmes Unix et Linux, si tant est
quelles ne prennent pas toutes en charge loption -q.

Voir aussi

man grep ;

man regex (Linux, Solaris, HP-UX) ou man re_format (BSD, Mac) pour tous les
dtails concernant votre bibliothque dexpressions rgulires ;

Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

154

Chapitre 7 Outils shell intermdiaires I

7.4. Rechercher une chane en ignorant la casse


Problme
Vous souhaitez rechercher une chane (par exemple, erreur ) dans un fichier de journalisation, mais sans tenir compte de la casse, afin dobtenir toutes les occurrences.

Solution
Utilisez loption -i de grep, qui ignore la place :
$ grep -i erreur journal.msgs

Discussion
Cette forme de recherche trouvera les messages qui contiennent le mot ERREUR ,
erreur ou Erreur , mais galement ErrEUR ou eRrEUr . Cette option est
particulirement utile pour rechercher des mots qui pourraient mlanger les minuscules et les majuscules, notamment ceux placs au dbut dune phrase ou dune adresse de
messagerie.

Voir aussi

man grep ;

man regex (Linux, Solaris, HP-UX) ou man re_format (BSD, Mac) pour tous les
dtails concernant votre bibliothque dexpressions rgulires ;

Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) ;

la prsentation de la commande find et de son option -iname au chapitre 9 ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490.

7.5. Effectuer une recherche dans un tube


Problme
Vous souhaitez rechercher du texte, mais il ne se trouve pas dans un fichier. En ralit,
il sagit de la sortie dune commande ou mme de la sortie de commandes enchanes.

Solution
Envoyez les rsultats grep via un tube :
$ un tube | de commandes | grep

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.5. Effectuer une recherche dans un tube

155

Discussion
Lorsquaucun nom de fichier nest donn grep, cette commande lit depuis lentre standard. Cest le cas de la plupart des outils bien conus et destins une utilisation dans
des scripts. Cest pour cette raison quils sont constituent des lments de base de lcriture de scripts shell.
Si vous souhaitez que grep recherche des messages derreur issus de la commande prcdente, commencez par rediriger lerreur standard vers la sortie standard :
$ gcc mauvais_code.c 2>&1 | grep -i error

Cette ligne de commande tente de compiler du code rempli derreurs. Nous dirigeons
lerreur standard vers la sortie standard (2>&1) avant denvoyer (|) la sortie grep, qui
recherche, sans tenir compte de la casse (-i), la chane error.
Vous avez galement la possibilit denvoyer la sortie de grep vers une autre commande
grep. Cette solution permet de rduire les rsultats dune recherche. Par exemple, supposons que vous souhaitiez trouver ladresse lectronique de Bob Johnson :
$ grep -i johnson mail/*
... la sortie est trop longue pour tre intressante
car les Johnsons sont nombreux sur Terre ...
$ !! | grep -i robert
grep -i johnson mail/* | grep -i robert
... la sortie devient plus intressante ...
$ !! | grep -i "le bluesman"
grep -i johnson mail/* | grep -i robert | grep -i "le bluesman"
Robert M. Johnson, Le Bluesman <rmj@nullepart.org>

Vous auriez pu rpter la premire commande grep, mais cet exemple montre galement tout lintrt de loprateur !!. Il permet de rpter la commande prcdente sans
la saisir nouveau. Vous pouvez poursuivre la ligne de commande aprs loprateur !!,
comme nous lavons fait dans cet exemple. Puisque le shell affiche la commande quil
excute, vous savez ce que gnre le remplacement de !! (voir la recette 18.2, page 477).
Grce cette approche, vous pouvez construire trs rapidement et simplement un long
tube grep. Vous pouvez examiner les rsultats des tapes intermdiaires et dcider daffiner la recherche laide dexpressions grep supplmentaires. La mme tche peut tre
ralise avec une seule commande grep et une expression rgulire plus labore, mais
nous pensons quil est plus facile de construire un tube tape par tape.

Voir aussi

man grep ;

man regex (Linux, Solaris, HP-UX) ou man re_format (BSD, Mac) pour tous les
dtails concernant votre bibliothque dexpressions rgulires ;

Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) ;

la recette 2.15, Relier une sortie une entre, page 46 ;

la recette 18.2, Rpter la dernire commande, page 477 ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

156

Chapitre 7 Outils shell intermdiaires I

7.6. Rduire les rsultats de la recherche


Problme
La recherche retourne un trop grand nombre dinformations, y compris des rsultats
inutiles.

Solution
Dirigez les rsultats vers grep -v avec une expression qui dcrit ce que vous souhaitez
retirer.
Supposons que vous recherchiez des messages dans un fichier de journalisation et que
seuls ceux du mois de dcembre vous intressent. Vous savez que votre journal utilise
labrviation Dec pour dcembre, mais vous ntes pas certain que ce mois est toujours
crit ainsi. Pour tre certain sr de trouver toutes les versions, vous saisissez la commande suivante :
$ grep -i dec journal

Vous obtenez alors la sortie suivante :


...
error on Jan 01: nombre non decimal
error on Feb 13: base convertie en Decimal
warning on Mar 22: utiliser uniquement des nombres decimaux
error on Dec 16: le message que vous recherchez
error on Jan 01: nombre non decimal
...

Une solution rapide ce problme consiste envoyer le premier rsultat vers un deuxime grep et dindiquer celui-ci dignorer les instances de decimal :
$ grep -i dec journal | grep -vi decimal

Il est assez frquent de combiner ainsi plusieurs commandes grep (lorsque de nouvelles
correspondances inutiles sont dcouvertes) afin de filtrer les rsultats dune recherche.
Par exemple :
$ grep -i dec journal | grep -vi decimal | grep -vi decimer

Discussion
Cette solution a pour inconvnient de retirer certains messages du mois de dcembre
sils contiennent galement le mot decimal . Loption -v sera pratique si elle est utilise avec prudence. Vous devez tout simplement faire attention ce quelle peut exclure.
Dans notre exemple, une meilleure solution consiste utiliser une expression ou rgulire plus labore qui trouve les correspondances avec le mois de dcembre suivi dune
espace et de deux chiffres :
$ grep 'Dec [0-9][0-9]' journal

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.7. Utiliser des motifs plus complexes dans la recherche

157

Mais cela ne fonctionnera pas toujours car syslog utilise une espace pour combler les dates constitues dun seul chiffre. Nous devons donc ajouter une espace dans la premire
liste [0-9] :
$ grep 'Dec [0-9 ][0-9]' journal

Lexpression est place entre apostrophes car elle contient des espaces. Cela permet galement dviter une interprtation des crochets par le shell (ils ne le seront pas, mais
cest une question dhabitude). Il est prfrable de shabituer entourer dapostrophes
tout ce qui pourrait perturber le shell. Nous aurions pu crire la ligne suivante :
$ grep Dec\ [0-9\ ][0-9] journal

Lespace est chappe avec une barre oblique inverse. Mais, sous cette forme, il est plus
difficile de dterminer la fin de la chane et le dbut du nom du fichier.

Voir aussi

man grep ;

man regex (Linux, Solaris, HP-UX) ou man re_format (BSD, Mac) pour tous les
dtails concernant votre bibliothque dexpressions rgulires ;

Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490.

7.7. Utiliser des motifs plus complexes dans la


recherche
Les expressions rgulires de grep offrent des motifs trs puissants qui satisferont pratiquement tous vos besoins.
Une expression rgulire dcrit les motifs servant la comparaison avec les chanes. Tout
caractre alphabtique correspond ce caractre prcis dans la chane. Autrement dit,
A correspond A , B B , etc. Mais les expressions rgulires dfinissent
dautres caractres particuliers qui peuvent tre employs seuls ou en combinaison avec
dautres caractres pour construire des motifs plus complexes.
Nous avons dj expliqu que tout caractre sans signification particulire correspond
simplement lui-mme ; A A , etc. La rgle suivante consiste combiner des
lettres en fonction de leur emplacement. Ainsi AB correspond A suivi de
B . Malgr tout, elle semble trop vidente.
Le premier caractre particulier est le point (.). Un point correspond nimporte quel
caractre unique. Par consquent, .... correspond quatre caractres, A. A suivi
de nimporte quel caractre et .A. nimporte quel caractre, suivi de A , suivi de
nimporte quel caractre (pas ncessairement le mme caractre que le premier).
Un astrisque (*) indique la rptition daucune ou plusieurs occurrences du caractre
prcdent. A* correspond donc zro ou plusieurs caractres A et .* signifie zro ou
plusieurs caractres quelconques (par exemple abcdefg , aaaabc , sdfgf ;lkjhj
ou mme une ligne vide)

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

158

Chapitre 7 Outils shell intermdiaires I

Alors, que signifie donc ..* ? Il sagit de tout caractre unique suivi de zro ou plusieurs
caractres quelconques (autrement dit, un ou plusieurs caractres), mais non une ligne
vide.
Le caractre accent circonf lexe (^) correspond au dbut dune ligne de texte et le symbole dollar ($) correspond la fin de ligne. Par consquent, ^$ dsigne une ligne vide
(le dbut suivi dune fin de ligne, sans rien entre les deux).
Pour ajouter un point, un accent circonf lexe, un dollar ou tout autre caractre particulier dans le motif, faites-le prcder dune barre oblique inverse (\). Ainsi, ion. correspond aux lettres ion suivi de nimporte quelle autre lettre, mais ion\. correspond
ion suivi dun point.
Un jeu de caractres placs entre crochets, par exemple [abc], correspond nimporte
lequel de ces caractres (par exemple, a ou b ou c ). Si le premier caractre
lintrieur des crochets est un accent circonflexe, alors la correspondance se fait avec
tout caractre qui ne se trouve pas dans le jeu indiqu.
Par exemple, [AaEeIiOoUu] correspond nimporte quelle voyelle, tandis que [^AaEeIiOoUu] correspond nimporte quel caractre qui nest pas une voyelle. Notez que cela
nest pas quivalent une correspondance avec les consonnes car [^AaEeIiOoUu] inclut
galement les symboles de ponctuation et les autres caractres spciaux qui ne sont ni
des voyelles ni des consonnes.
Enfin, vous pouvez employer un mcanisme de rptition qui scrit sous la forme
\{n,m\}, o n indique le nombre minimum de rptition et m le nombre maximum.
Donn sous la forme \{n\}, il signifie exactement n fois , tandis qucrit \{n,\} ,
il reprsente au moins n fois .
Par exemple, lexpression rgulire A\{5\} quivaut cinq lettres A majuscules la suite, tandis que A\{5,\} correspond cinq lettres A majuscules ou plus.

7.8. Rechercher un numro de scu


Problme
Vous avez besoin dune expression rgulire pour rechercher un numro de scurit sociale amricain1. Ces numros sont constitus de neuf chiffres, regroups en plusieurs
parties (123-45-6789), avec ou sans les tirets, qui doivent tre facultatifs.

Solution
$ grep '[0-9]\{3\}-\{0,1\}[0-9]\{2\}-\{0,1\}[0-9]\{4\}' fichier

1. N.d.T. : Cela fonctionne galement avec les numros de scurit sociale franais, mais leur
format est moins intressant pour lexemple.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.9. Rechercher dans les fichiers compresss

159

Discussion
Ces expressions rgulires sont souvent dites en criture seule, car, une fois crites, elles
sont difficiles voire impossibles lire. Nous allons dcomposer celle-ci afin de bien la
comprendre. Cependant, lorsque vous crivez un script bash qui sappuie sur les expressions rgulires, noubliez pas dajouter des commentaires qui dcrivent parfaitement
les correspondances recherches par ces expressions.
En ajoutant des espaces lexpression rgulire, nous pouvons amliorer sa lisibilit,
mais nous modifions galement son sens. Cela signifierait que des espaces sont ncessaires l o elles sont indiques dans lexpression. Oublions cela pour le moment et ajoutons quelques espaces dans lexpression rgulire prcdente afin de la rendre plus
lisible :
[0-9]\{3\}

-\{0,1\}

[0-9]\{2\}

-\{0,1\} [0-9]\{4\}

Le premier groupe indique nimporte quel chiffre puis exactement 3 fois . Le


groupe suivant prcise un tiret puis 0 ou 1 fois . Le troisime groupe signifie
nimporte quel chiffre puis exactement 2 fois . Le quatrime groupe reprsente
un tiret puis 0 ou 1 fois . Le dernier groupe indique nimporte quel chiffre
puis exactement 4 fois

Voir aussi

man regex (Linux, Solaris, HP-UX) ou man re_format (BSD, Mac) pour tous les
dtails concernant votre bibliothque dexpressions rgulires ;

Introduction aux scripts shell de Nelson H.F. Beebe et Arnold Robbins (ditions
OReilly), section 3.2, pour en savoir plus sur les expressions rgulires et les outils
qui les utilisent ;

Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490.

7.9. Rechercher dans les fichiers compresss


Problme
Vous souhaitez effectuer une recherche dans des fichiers compresss. Devez-vous commencer par les dcompresser ?

Solution
En aucun cas, si les commandes zgrep, zcat ou gzcat sont installes sur votre systme.
zgrep est simplement une commande grep qui sait comment traiter les diffrents fichiers
compresss ou non (les types reconnus varient dun systme lautre). Elle est souvent
employe sous Linux pour des recherches dans les messages de syslog, puisque cet outil
maintient une version non compresse du fichier de journalisation courant (pour pouvoir le consulter) et des archives compresses :
$ zgrep 'terme recherch' /var/log/messages*

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

160

Chapitre 7 Outils shell intermdiaires I

zcat est simplement une commande cat qui sait interprter les diffrents fichiers compresss ou non (les types reconnus varient dun systme lautre). Elle reconnat un plus
grand nombre de formats que zgrep et elle est probablement installe par dfaut sur un
plus grand nombre de systmes. Elle sert galement dans la rcupration de fichiers
compresss endommags, puisquelle affiche tout ce quelle parvient lire au lieu de se
terminer sur une erreur, comme gunzip ou dautres outils.
gzcat est similaire zcat. Les diffrences concernent les variantes commerciales et gratuites dUnix, ainsi que la rtro-compatibilit :
$ zcat /var/log/messages.1.gz

Discussion
Le programme less peut galement tre configur pour prendre en charge diffrents fichiers compresss (voir la recette 8.15, page 189).

Voir aussi

la recette 8.6, Compresser les fichiers, page 178 ;

la recette 8.7, Dcompresser des fichiers, page 180 ;

la recette 8.15, Aller plus loin avec less, page 189.

7.10. Garder une partie de la sortie


Problme
Vous souhaitez conserver uniquement une partie de la sortie et carter le reste.

Solution
Le code suivant affiche le premier mot de chaque ligne en entre :
$ awk '{print $1}' monEntree.fichier

Les mots sont dlimits par des espaces. awk lit les donnes depuis le nom de fichier indiqu sur la ligne de commande ou depuis lentre standard si aucun nom nest donn.
Par consquent, vous pouvez rediriger lentre depuis un fichier ainsi :
$ awk '{print $1}' < monEntree.fichier

Vous pouvez mme utiliser un tube :


$ cat monEntree.fichier | awk '{print $1}'

Discussion
Le programme awk peut tre employ de diffrentes manires. Sous sa forme la plus
simple, il affiche simplement un ou plusieurs champs slectionns de lentre.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.11. Conserver une partie dune ligne de sortie

161

Les champs sont dlimits par des espaces (ou indiqus avec loption -F) et sont numrots partir de 1. Le champ $0 reprsente lintgralit de la ligne en entre.
awk est un langage de programmation complet. Les scripts awk peuvent tre trs complexes. Cet exemple nest quun dbut.

Voir aussi

man awk ;

http://www.faqs.org/faqs/computer-lang/awk/faq/ ;

Effective awk Programming dArnold Robbins (OReilly Media) ;

sed & awk dArnold Robbins et Dale Dougherty (OReilly Media).

7.11. Conserver une partie dune ligne de sortie


Problme
Vous souhaitez ne garder quune partie dune ligne de sortie, comme le premier et le
dernier mots. Par exemple, vous aimeriez que ls affiche uniquement les noms de fichiers et les autorisations, sans les autres informations fournies par ls -l. Cependant, ls
ne semble proposer aucune option qui configure ainsi la sortie.

Solution
Envoyez ls vers awk et conservez uniquement les champs ncessaires :
$ ls -l | awk '{print $1, $NF}'
total 151130
-rw-r--r-- add.1
drwxr-xr-x art
drwxr-xr-x bin
-rw-r--r-- BuddyIcon.png
drwxr-xr-x CDs
drwxr-xr-x downloads
drwxr-sr-x eclipse
...
$

Discussion
Examinons le rsultat de la commande ls -l. Voici le format dune ligne :
drwxr-xr-x

2 utilisateur groupe

176 2006-10-28 20:09 bin

Elle est parfaitement adapte un traitement par awk, puisque, par dfaut, les espaces
dlimitent les champs. Dans la sortie gnre par ls -l, les autorisations constituent le
premier champ et le nom de fichier se trouve dans le dernier.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

162

Chapitre 7 Outils shell intermdiaires I

Nous utilisons une petite astuce pour afficher le nom de fichier. Dans awk, les champs
sont rfrencs laide dun symbole dollar suivi du numro du champ (par exemple,
$1, $2, $3). Dautre part, awk possde une variable interne nomme NF qui prcise le
nombre de champs trouvs sur la ligne en cours. Par consquent, $NF fait toujours rfrence au dernier champ. Par exemple, une ligne du rsultat de ls est constitue de huit
champs. La variable NF contient donc la valeur 8 et $NF fait rfrence au huitime
champ de la ligne reue en entre, ce qui correspond au nom de fichier.
Noubliez pas que la lecture dune variable awk se fait sans le symbole $ (contrairement
aux variables de bash). NF est une rfrence de variable tout fait valide. Si vous y ajoutez un caractre $, sa signification nest plus le nombre de champs de la ligne en
cours , mais le dernier champ de la ligne en cours .

Voir aussi

man awk ;

http://www.faqs.org/faqs/computer-lang/awk/faq/ ;

Effective awk Programming dArnold Robbins (OReilly Media) ;

sed & awk dArnold Robbins et Dale Dougherty (OReilly Media).

7.12. Inverser les mots de chaque ligne


Problme
Vous souhaitez afficher les lignes dentre en inversant lordre des mots.

Solution
$ awk '{
>
for (i=NF; i>0; i--) {
>
printf "%s ", $i;
>
}
>
printf "\n"
> }'

Vous navez pas saisir les caractres >. Ils sont affichs par le shell en tant quinvite afin
de vous indiquer que vous navez pas encore termin la commande (il attend que vous
entriez lapostrophe finale). Puisque le programme awk est plac entre des apostrophes,
bash vous laisse saisir plusieurs lignes, en affichant linvite secondaire, >, jusqu ce que
lapostrophe fermante soit donne. Nous avons indent le programme pour des questions de lisibilit, mais vous pouvez lcrire sur une seule ligne :
$ awk '{for (i=NF; i>0; i--) {printf "%s ", $i;} printf "\n" }'

Discussion
En awk, la syntaxe dune boucle for est trs similaire celle du langage C. Il propose
mme une instruction printf de mise en forme de la sortie calque sur celle du langage
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.13. Additionner une liste de nombres

163

C (ou celle de bash). La boucle for effectue un dcompte, partir du dernier champ
vers le premier, et affiche chaque champ au fur et mesure. Nous navons pas ajout le
caractre \n au premier printf, car nous voulons que les champs restent sur la mme
ligne de sortie. Lorsque la boucle est termine, nous ajoutons un saut de ligne pour terminer la ligne en cours.
Compare bash, la rfrence $i dans awk est trs diffrente. Dans bash, nous crivons
$i pour obtenir la valeur stocke dans la variable nomme i. Mais, en awk, comme dans
la plupart des langages de programmation, nous faisons rfrence la valeur de i en
nommant simplement cette variable, autrement dit en crivant directement i. Par consquent, que signifie donc $i en awk ? La valeur de la variable i est convertie en un
nombre et lexpression dollar-nombre est interprte comme une rfrence un champ
(ou un mot) de lentre, cest--dire le champ lemplacement i. Ainsi, i va du numro
du dernier champ au premier et la boucle affiche donc les champs dans lordre invers.

Voir aussi

man printf(1) ;

man awk ;

http://www.faqs.org/faqs/computer-lang/awk/faq/ ;

Effective awk Programming dArnold Robbins (OReilly Media) ;

sed & awk dArnold Robbins et Dale Dougherty (OReilly Media) ;

la section printf, page 540.

7.13. Additionner une liste de nombres


Problme
Vous souhaitez additionner une liste de nombres, y compris ceux qui napparaissent pas
au sein dune ligne.

Solution
Utilisez awk pour isoler les champs additionner et effectuer la somme. Voici comment
additionner les tailles des fichiers qui se trouvent sur la sortie dune commande ls -l :
$ ls -l | awk '{somme += $5} END {print somme}'

Discussion
Nous additionnons le cinquime champ du rsultat de ls -l, qui ressemble la ligne
suivante :
-rw-r--r--

1 albing users 267 2005-09-26 21:26 lilmax

Les diffrents champs sont les autorisations, les liens, le propritaire, le groupe, la taille
(en octets), la date, lheure et le nom de fichier. Seule la taille nous intresse et nous utilisons donc $5 dans le programme awk pour faire rfrence ce champ.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

164

Chapitre 7 Outils shell intermdiaires I

Les deux corps de notre programme awk sont placs entre accolades ({}). Un programme awk peut tre constitu de plusieurs corps (ou bloc) de code. Un bloc de code prcd du mot-cl END est excut une seule fois, lorsque le reste du programme est termin.
De manire similaire, vous pouvez prfixer un bloc de code par BEGIN, qui sera alors
excut avant la lecture de toute entre. Le bloc BEGIN sert gnralement initialiser des
variables. Nous aurions pu lemployer dans notre exemple pour initialiser la somme,
mais awk garantit que les variables sont initialement vides.
Si vous examinez laffichage produit par une commande ls -l, vous noterez que la premire ligne reprsente un total et quelle ne correspond pas au format attendu pour les
autres lignes.
Nous avons deux manires de grer ce problme. Nous pouvons prtendre que cette
premire ligne nexiste pas ; cest lapproche prise prcdemment. Puisque la ligne na
pas de cinquime champ, la rfrence $5 est vide et la somme nest pas affecte.
Une meilleure approche consiste liminer la ligne. Nous pouvons le faire avant de passer la sortie awk en utilisant grep :
$ ls -l | grep -v '^total' | awk '{somme += $5} END {print somme}'

Ou bien, lintrieur du programme awk :


$ ls -l | awk '/^total/{getline} {somme += $5} END {print somme}'

^total est une expression rgulire qui signifie les lettres t-o-t-a-l places en dbut de
ligne (le caractre ^ ancre la recherche en dbut de ligne). Pour toutes les lignes qui
correspondent cette expression rgulire, le bloc de code associ est excut. Le deuxime bloc de code (la somme) ne contient pas dinstructions initiales et awk lexcute
donc pour chaque ligne dentre (quelle corresponde ou non lexpression rgulire).
Lajout du cas particulier pour total a pour objectif dexclure ce type de lignes dans
le calcul de la somme. Par consquent, dans le bloc ^total, nous avons ajout une commande getline qui passe la ligne dentre suivante. Lorsque le deuxime bloc de code
est atteint, il reoit donc une nouvelle ligne dentre. La commande getline ne reprend
pas les correspondances des motifs partir du dbut. En programmation awk, lordre
des blocs de code est important.

Voir aussi

man awk ;

http://www.faqs.org/faqs/computer-lang/awk/faq/ ;

Effective awk Programming dArnold Robbins (OReilly Media) ;

sed & awk dArnold Robbins et Dale Dougherty (OReilly Media).

7.14. Compter des chanes


Problme
Vous souhaitez comptabiliser les occurrences de diffrentes chanes, y compris des chanes dont vous ignorez la valeur. Autrement dit, vous ne voulez pas compter les occur-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.14. Compter des chanes

165

rences dun ensemble de chanes prdtermines, mais connatre le nombre de chanes


contenues dans vos donnes.

Solution
Utilisez les tableaux associatifs de awk (galement appels tables de hachage) pour les
compter.
Dans notre exemple, nous comptons le nombre de fichiers appartenant aux diffrents
utilisateurs du systme. Le nom dutilisateur se trouve dans le troisime champ de la
sortie dune commande ls -l. Nous utilisons donc ce champ ($3) comme indice du tableau et incrmentons la valeur associe :
#
# bash Le livre de recettes : entableau.awk
#
NF > 7 {
utilisateur[$3]++
}
END {
for (i in utilisateur)
{
printf "%s dtient %d fichiers\n", i, utilisateur[i]
}
}

Dans cet exemple, linvocation de awk est lgrement diffrente. Puisque ce script awk
est un peu plus complexe, nous lenregistrons dans un fichier spar. Nous utilisons
loption -f pour indiquer awk o se trouve le fichier du script :
$ ls -lR /usr/local | awk -f asar.awk
bin dtient 68 fichiers
albing dtient 1801 fichiers
root dtient 13755 fichiers
man dtient 11491 fichiers
$

Discussion
La condition NF > 7 nous permet de diffrencier les parties du script awk et dcarter les
lignes qui ne contiennent aucun nom de fichier. Elles apparaissent dans la sortie de ls
-lR et amliorent la lisibilit car il sagit de lignes vides qui sparent les diffrents rpertoires ainsi que de lignes de total pour chaque sous-rpertoire. Ces lignes contiennent
peu de champs (ou mots). Lexpression NF>7 qui prcde laccolade ouvrante nest pas
place entre des barres obliques car il ne sagit pas dune expression rgulire, mais
dune expression logique, semblable celle des instructions if, qui svalue vrai ou
faux. La variable interne NF fait rfrence au nombre de champs de la ligne dentre en
cours. Si une ligne dentre contient plus de sept champs, elle est donc traite par les instructions places entre les accolades.
Cependant, la ligne importante est la suivante :
utilisateur[$3]++

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

166

Chapitre 7 Outils shell intermdiaires I

Le nom dutilisateur (par exemple, bin) sert dindice du tableau. Il sagit dun tableau associatif car une table de hachage (ou un mcanisme similaire) permet dassocier chaque
chane unique un indice numrique. awk effectue tout ce travail votre place et vous
navez donc pas mettre en uvre des comparaisons de chanes ou des recherches.
Une fois le tableau construit, vous pourriez penser que laccs aux valeurs est complexe.
Pour cela, awk propose une version particulire de la boucle for. la place de la forme
numrique for(i=0; i<max; i++), awk dispose dune syntaxe rserve aux tableaux
associatifs :
for (i in utilisateur)

Dans cette expression, la variable i prend successivement les valeurs (dans un ordre
quelconque) qui ont servi dindices au tableau utilisateur. Dans notre exemple, cela
signifie que i aura des valeurs diffrentes (bin, albing, man, root) chaque itration de
la boucle. Si vous naviez encore jamais rencontr de tableaux associatifs, nous esprons
que vous tes surpris et impressionn, il sagit dune caractristique trs puissante de
awk (et de Perl).

Voir aussi

man awk ;

http://www.faqs.org/faqs/computer-lang/awk/faq/ ;

Effective awk Programming dArnold Robbins (OReilly Media) ;

sed & awk dArnold Robbins et Dale Dougherty (OReilly Media).

7.15. Afficher les donnes sous forme


dhistogramme
Problme
Vous avez besoin dun histogramme rapide de certaines donnes.

Solution
Utilisez les tableaux associatifs de awk, comme nous lavons expliqu la recette prcdente :
#
# bash Le livre de recettes : hist.awk
#
function max(tab, sup)
{
sup = 0;
for (i in utilisateur)
{
if (utilisateur[i] > sup) { sup=utilisateur[i];}
}

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.15. Afficher les donnes sous forme dhistogramme

167

return sup
}
NF > 7 {
utilisateur[$3]++
}
END {
# Pour les proportions.
maxm = max(utilisateur);
for (i in utilisateur)
{
#printf "%s dtient %d fichiers\n", i, utilisateur[i]
echelle = 60 * utilisateur[i] / maxm ;
printf "%-10.10s [%8d]:", i, utilisateur[i]
for (i=0; i<echelle; i++) {
printf "#";
}
printf "\n";
}
}

Lexcution de ce programme sur la mme entre que la recette prcdente produit le


rsultat suivant :
$ ls -lR
bin
albing
root
man
$

/usr/local | awk -f hist.awk


[
68]:#
[
1801]:#######
[
13755]:##################################################
[ 11491]:##########################################

Discussion
Nous aurions pu placer le code de max au dbut du bloc END, mais nous voulions montrer comment dfinir des fonctions en awk. Nous utilisons une version un peu plus labore de printf. Le format %-10.10s aligne droite la chane de caractres, mais la
comble et la tronque galement 10 caractres. Le format numrique %8d sassure que
lentier est affich dans un champ de 8 caractres. De cette manire, chaque histogramme commence au mme point, quels que soient le nom de lutilisateur et la taille de
lentier.
Comme toutes les oprations arithmtiques en awk, le calcul des proportions se fait en
virgule flottante, except si le rsultat est explicitement tronqu par un appel la fonction interne int( ). Ce nest pas le cas dans notre exemple. La boucle for sexcutera
donc au moins une fois et mme la plus petite quantit de donnes sera affiche sous
forme dun seul symbole dise.
Lordre des donnes renvoyes par la boucle for (i in utilisateur) nest pas prcis,
mais il correspond probablement un ordre adapt la table de hachage sous-jacente.
Si vous souhaitez trier lhistogramme, en fonction de la taille numrique ou des noms
dutilisateurs, vous devez ajouter une forme de tri. Pour cela, vous pouvez dcouper ce

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

168

Chapitre 7 Outils shell intermdiaires I

programme en deux parties et envoyer la sortie de la premire vers la commande sort,


dont la sortie doit tre redirige vers la deuxime partie du programme qui affiche
lhistogramme.

Voir aussi

man awk ;

http://www.faqs.org/faqs/computer-lang/awk/faq/ ;

Effective awk Programming dArnold Robbins (OReilly Media) ;

sed & awk dArnold Robbins et Dale Dougherty (OReilly Media) ;

la recette 8.1, Trier votre affichage, page 171.

7.16. Afficher un paragraphe de texte aprs


une phrase trouve
Problme
Vous recherchez une phrase dans un document et souhaitez afficher le paragraphe aprs
la phrase trouve.

Solution
Dans le fichier texte, nous supposons quun paragraphe est dlimit par des lignes vides.
En faisant cette hypothse, voici un court programme awk :
$ cat para.awk
/phrase/ { indic=1 }
{ if (indic == 1) { print $0 } }
/^$/ { indic=0 }
$
$ awk -f para.awk < text.txt

Discussion
Ce programme est constitu de trois blocs de code simples. Le premier est invoqu lorsquune ligne dentre correspond lexpression rgulire (dans ce cas, uniquement le
mot phrase ). Si phrase se trouve nimporte o dans la ligne dentre, une correspondance est trouve et le bloc de code est excut. Il fixe simplement la variable indic
1.
Le deuxime bloc de code est invoqu pour chaque ligne dentre, car aucune expression rgulire ne prcde son accolade ouvrante. Mme une ligne qui contient le mot
phrase est traite par ce bloc de code (si ce fonctionnement nest pas souhait, placez
une instruction continue dans le premier bloc). Le code du deuxime bloc affiche simplement la ligne dentre complte, mais uniquement si la variable indic vaut 1.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

7.16. Afficher un paragraphe de texte aprs une phrase trouve

169

Le troisime bloc de code commence par une expression rgulire qui, si elle est satisfaite, rinitialise simplement la variable indic. Cette expression rgulire emploie deux
caractres ayant une signification particulire. Laccent circonf lexe (^), utilis en premier caractre de lexpression rgulire, correspond au dbut de la ligne. Le symbole
($), utilis en dernier caractre, correspond la fin de la ligne. Lexpression rgulire ^$
signifie donc une ligne vide , car il ny a aucun caractre entre le dbut et la fin de la
ligne.
Nous pouvons crire une expression rgulire un peu plus complexe pour quune ligne
contenant uniquement des espaces soit galement considre comme une ligne vide.
Dans ce cas, la troisime ligne du script devient la suivante :
/^[:blank:]*$/ { indic=0 }

Les programmeurs Perl affectionnent particulirement le genre de problme et la solution dcrits dans cette recette, mais nous avons choisi awk car Perl sort (en grande partie)
du cadre de ce livre. Si vous savez programmer en Perl, utilisez ce langage. Sinon, awk
peut rpondre vos besoins.

Voir aussi

man awk ;

http://www.faqs.org/faqs/computer-lang/awk/faq/ ;

Effective awk Programming dArnold Robbins (OReilly Media) ;

sed & awk dArnold Robbins et Dale Dougherty (OReilly Media).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8
Outils shell intermdiaires II

Une fois de plus, nous avons quelques outils utiles qui ne font pas partie du shell, mais
qui servent tant de scripts que vous devez les connatre.
Les tris sont des tches tellement habituelles, et utiles pour amliorer la lisibilit, quil
est bon de connatre la commande sort. Dans la mme veine, la commande tr effectue
des traductions et des remplacements caractre par caractre, de mme quelle peut en
supprimer.
Ces outils prsentent le point commun de ne pas tre crits comme des commandes
autonomes, mais comme des filtres qui peuvent tre inclus dans des commandes enchanes avec des redirections. Ce type de commandes prend en gnral un ou plusieurs
noms de fichier en paramtre (ou argument) mais, en absence de nom de fichier, ces
commandes utiliseront lentre standard. Elles crivent sur la sortie standard. Cette
combinaison facilite les connexions entre ces commandes grce des tubes, comme
dans quelquechose | sort | autrechose.
Cela les rend particulirement pratiques et vite la confusion rsultant de trop nombreux fichiers temporaires.

8.1. Trier votre affichage


Problme
Vous aimeriez que laffichage apparaisse tri. Mais vous ne voulez pas crire (une fois
de plus) une fonction de tri personnelle dans votre programme ou votre script. Cette
fonctionnalit existe-t-elle dj ?

Solution
Utilisez loutil sort. Vous pouvez trier un ou plusieurs fichiers en plaant leur nom sur
la ligne de commande :
$ sort fichier1.txt fichier2.txt monautrefichier.xyz
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

172

Chapitre 8 Outils shell intermdiaires II

Sans nom de fichier sur la ligne de commande, sort lira depuis lentre standard et vous
pourrez injecter le rsultat dune autre commande dans sort :
$ commandes | sort

Discussion
Il peut tre pratique de disposer dun affichage tri sans avoir ajouter du code vos
programmes et scripts pour effectuer ce tri. Les tubes du shell vous permettent dinsrer
sort la sortie standard de tous les programmes.
sort comporte plusieurs options, mais deux dentre elles sont les plus importantes :
$ sort -r

pour inverser lordre du tri (o, comme le dit la citation, les premiers seront les derniers
et les derniers seront les premiers) et
$ sort -f

pour regrouper 1 les minuscules et les majuscules ensemble. En dautres termes, cette option ignore la casse. Il est aussi possible dutiliser loption au format GNU long :
$ sort --ignore-case

Nous avons dcid de faire durer le suspens, consultez la recette suivante pour connatre
la troisime option de sort.

Voir aussi

man sort ;

la recette 8.2, Trier les nombres, page 172.

8.2. Trier les nombres


Problme
Lorsque vous triez des donnes numriques, vous remarquez que lordre du tri semble
incorrect :
$ sort nombres.txt
2
200
21
250
$

Solution
Vous devez indiquer sort que les donnes trier sont des nombres. Pour cela, utilisez
loption -n :
1. N.d.T. : f pour le verbe to fold en anglais pourrait aussi se traduire par replier .

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8.3. Trier des adresses IP

173

$ sort -n nombres.txt
2
21
200
250
$

Discussion
Lordre de tri initial nest pas faux ; loutil effectue un tri alphabtique sur les donnes
(21 se situe aprs 200 car 1 se trouve aprs 0, dans un tri alphabtique). Bien sr, vous
prfrerez certainement avoir un tri numrique et vous devrez utiliser loption -n.
sort -rn peut tre particulirement pratique pour donner une liste dcroissante de frquences quelconque en le couplant uniq -c. Par exemple, affichons les shells les plus
populaires de ce systme :
$ cut -d':' -f7 /etc/passwd | sort | uniq -c | sort -rn
20 /bin/sh
10 /bin/false
2 /bin/bash
1 /bin/sync

cut -d':' -f7 /etc/passwd isole la chane indiquant le shell dans le fichier /etc/passwd.
Puis nous devons effectuer un premier pr-tri pour que uniq puisse compter les doublons conscutifs. Ensuite, sort -rn retourne une liste dcroissante, trie numriquement, avec les interprteurs de commandes les plus populaires en tte.
Si vous navez pas besoin de compter les occurrences et que vous ne voulez que la liste
des valeurs uniques (sans doublons), vous pouvez utiliser loption -u de la commande
sort (et omettre la commande uniq). Ainsi, pour connatre la liste des diffrents interprteurs utiliss sur le systme, vous pouvez excuter :
cut -d':' -f7 /etc/passwd | sort -u

Voir aussi

man sort ;

man uniq ;

man cut.

8.3. Trier des adresses IP


Problme
Vous voulez trier une liste dadresses IP numriques mais vous voudriez que le tri se fasse uniquement sur la dernire portion de ladresse ou sur ladresse globale.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

174

Chapitre 8 Outils shell intermdiaires II

Solution
Pour trier en fonction du dernier octet (ancienne syntaxe) :
$ sort -t. -n +3.0 adressesIP.lst
10.0.0.2
192.168.0.2
192.168.0.4
10.0.0.5
192.168.0.12
10.0.0.20
$

Pour trier en fonction de la totalit de ladresse (syntaxe POSIX) :


$ sort -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n adressesIP.lst
10.0.0.2
10.0.0.5
10.0.0.20
192.168.0.2
192.168.0.4
192.168.0.12
$

Discussion
Nous savons quil sagit de donnes numriques et nous utilisons donc loption -n. Loption -t indique le caractre reconnatre comme sparateur entre les champs (dans notre cas, un point), ainsi nous pouvons prciser lordre selon lequel trier les champs. Dans
le premier exemple, nous commenons le tri avec le troisime champ (la numrotation
commence 0) partir de la gauche et par son tout premier caractre (la numrotation
commence, ici aussi, 0) de ce champ, soit +3.0.
Dans le second exemple, nous avons utilis la nouvelle spcification POSIX la place de
la mthode traditionnelle (et obsolte) +pos1 -pos2. Contrairement lancienne mthode, la numrotation ne commence pas 0 mais 1.
$ sort -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n adressesIP.lst

Comme cest compliqu ! Voici la mme commande avec lancienne syntaxe : sort -t.
+0n -1 +1n -2 +2n -3 +3n -4, qui nest gure plus lisible !
Lutilisation de -t. pour dfinir le dlimiteur de champ est la mme, mais les champs
employer sont indiqus autrement. Dans ce cas, -k 1,1n signifie la cl de tri commence au dbut du premier champ (1) et (,) sarrte la fin du premier champ (1) en faisant
un tri numrique (n) . Une fois que vous aurez acquis cela, le reste sera enfantin. Lors
de lutilisation de plusieurs champs, il est trs important dindiquer sort o sarrter.
Le comportement par dfaut place la fin de la cl de tri la fin de la ligne, ce qui nest
pas obligatoirement ce que vous souhaitez et cela peut vous poser problme si vous ne
connaissez pas ce comportement.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8.3. Trier des adresses IP

175

L'ordre que sort utilise est influenc par les rglages de localisation (les
paramtres rgionaux). Si vos rsultats ne sont pas ceux attendus, vrifiez ces paramtres.

Lordre du tri change dun systme un autre selon que la commande sort utilise un algorithme de tri stable par dfaut ou non. Un tel algorithme prserve lordre original
dans les donnes tries lorsque les champs de tri sont gaux. Linux et Solaris nutilisent
pas un algorithme stable par dfaut au contraire de NetBSD. De plus, si loption -S dsactive le tri stable sous NetBSD, elle configure la taille du tampon dans les autres versions de sort.
Si nous excutons cette commande sort sur un systme Linux ou Solaris :
$ sort -t. -k4n ipaddr.list

ou celle-ci sur un systme NetBSD :


$ sort -t. -S -k4n ipaddr.list

nous obtiendrons des donnes tries comme celles de la premire colonne du tableau 8-1.
Retirez le -S sur un systme NetBSD et sort triera les donnes comme celles de la deuxime colonne.
Tableau 8-1. Comparaison de l'ordre de tri sous Linux, Solaris et NetBSD
Linux et Solaris (par dfaut) et NetBSD (-S)

NetBSD (par dfaut)

10.0.0.2
192.168.0.2
10.0.0.4
192.168.0.4
192.168.0.12
10.0.0.20

192.168.0.2
10.0.0.2
192.168.0.4
10.0.0.4
192.168.0.12
10.0.0.20

#
#
#
#
#
#

sluggish
laptop
mainframe
office
speedy
lanyard

#
#
#
#
#
#

laptop
sluggish
office
mainframe
speedy
lanyard

Si notre fichier dentre, adressesIP.lst, avait toutes les adresses 192.168 en premier, suivies par toutes les adresses 10., le tri stable devrait laisser les adresses 192.168 en premier lorsquil trouve une galit entre les cls de deux lments. Nous pouvons voir
dans le tableau 8-1 que cette situation se produit pour les ordinateurs laptop et sluggish, dont les adresses se terminent par le chiffre 2 et pour les machines mainframe et
office, dont les adresses se terminent par un 4. Avec le tri par dfaut sous Linux (ou
sous NetBSD avec loption -S), lordre nest pas garanti.
Pour revenir une solution simple, et pour sentraner un peu, trions alphabtiquement notre liste dadresses IP. Nous voulons utiliser le caractre # comme sparateur et
effectuer le tri sur le second champ :
$ sort -t'#' -k2 adressesIP.lst
10.0.0.20
# lanyard
192.168.0.2
# laptop
10.0.0.5
# mainframe
192.168.0.4
# office
10.0.0.2
# sluggish
192.168.0.12
# speedy
$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

176

Chapitre 8 Outils shell intermdiaires II

La cl de tri commencera au second champ et, dans ce cas, ira jusqu la fin de la ligne.
Avec un seul sparateur (#) par ligne, nous navons pas besoin dindiquer une fin de cl,
mme si nous aurions pu ajouter -k2,2.

Voir aussi

man sort ;

lexemple ./functions/inetaddr de lannexe B, tel que fourni dans larchive des sources
bash.

8.4. Couper des parties de la sortie


Problme
Vous avez besoin de consulter uniquement une partie de donnes longueur fixe ou
en colonnes. Vous aimeriez conserver uniquement un sous-ensemble de ces donnes,
en fonction de la position horizontale (colonne).

Solution
Utilisez la commande cut avec loption -c pour slectionner certaines colonnes. Remarquez que, dans notre exemple, la commande 'ps' ne fonctionne quavec certains systmes (en loccurence, sous CentOS-4, Fedora Core 5 et Ubuntu mais pas sous Red Hat 8,
NetBSD, Solaris et Mac OS X qui utilisent des colonnes diffrentes) :
$ ps -l | cut -c12-15
PID
5391
7285
7286
$

ou :
$ ps -elf | cut -c58(affichage non copi)

Discussion
Avec la commande cut, nous indiquons la portion conserver dans chaque ligne. Dans
le premier exemple, nous gardons les colonnes de la douzime la quinzime, incluses.
Dans le second exemple, nous conservons les colonnes partir de la cinquante-huitime, car nous indiquons une colonne de dbut, mais pas de colonne de fin.
La plupart des donnes manipuler que nous avons rencontres sappuient sur des
champs, dont la position relative est donnes grce des dlimiteurs. La commande cut
peut aussi effectuer des slections sur de telles structures, mais cest une des seules commandes que vous utiliserez avec bash qui puisse aussi effectuer des slections dans des
donnes largeur de colonne fixe (avec loption -c).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8.5. Retirer les lignes identiques

177

Lutilisation de cut pour afficher des champs plutt que des colonnes est possible, bien
que plus limite que dautres outils comme awk. Le dlimiteur par dfaut est le caractre
de tabulation, mais vous pouvez en indiquer un autre laide de loption -d. Voici un
exemple de commande cut utilisant des champs :
$ cut -d'#' -f2 < adressesIP.lst

et la commande awk quivalente :


$ awk -F'#' '{print $2}' < adressesIP.lst

Vous pouvez aussi utiliser cut pour quil prenne en compte des dlimiteurs variables en
employant plusieurs commandes cut. Il serait prfrable dutiliser une expression rgulire avec awk pour cela, mais, dans certains cas, quelques commandes cut enchanes
sont plus vite dveloppes et tapes.
Voici comment vous pouvez obtenir le champ se trouvant entre crochets. Remarquez
que le premier cut utilise un crochet ouvrant (-d'[') comme dlimiteur et conserve le
second champ (-f2). Comme il a dj retir les caractres antrieurs au crochet ouvrant,
le second cut utilise un crochet fermant comme dlimiteur (-d']') et ne conserve que
le premier champ (-f1).
$ cat
Ligne
Ligne
Ligne

donnes_dlimites
[l1].
[l2].
[l3].

$ cut -d'[' -f2 donnes_dlimites | cut -d']' -f1


l1
l2
l3

Voir aussi

man cut ;

man awk.

8.5. Retirer les lignes identiques


Problme
Aprs avoir slectionn et/ou tri des donnes, vous remarquez que le rsultat comporte
de nombreuses lignes dupliques. Vous aimeriez les liminer de manire ne conserver
quune seule occurrence de chaque ligne.

Solution
Vous avez deux possibilits. Si vous avez utilis la commande de tri sort, vous pouvez
ajouter loption -u :
$ commandes | sort -u

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

178

Chapitre 8 Outils shell intermdiaires II

Si vous nutilisez pas sort, redirigez la sortie standard dans uniq (en supposant que le rsultat est tri et que les lignes dupliques sont donc adjacentes :
$ commandes > monfichier
$ uniq monfichier

Discussion
Comme uniq ncessite que les donnes soient pralablement tries, nous utiliserons
donc plus volontiers loption -u de sort moins que nous devions aussi compter le nombre de doublons (option -c, voir la recette 8.2, page 172), ou ne conserver que les lignes
dupliques (-d), ce que uniq peut faire.
N'crasez pas un fichier important par erreur ; les paramtres de la
commande uniq sont un peu surprenants. Alors que la plupart des
commandes Unix/Linux peuvent prendre plusieurs noms de fichier en
entre, uniq ne le peut pas. En fait, le premier argument ( ne pas confondre avec les options) est utilis comme seul et unique fichier
dentre et un second argument (sil y en a un) est interprt comme
fichier de sortie. Ainsi, si vous fournissez deux noms de fichier, le
second sera cras sans avertissement.

Voir aussi

man sort ;

man uniq ;

la recette 8.2, Trier les nombres, page 172.

8.6. Compresser les fichiers


Problme
Vous devez compresser certains fichiers et vous ntes pas certain de la meilleure mthode employer.

Solution
Tout dabord, vous devez comprendre que, sous Unix, larchivage et la compression des
fichiers sont deux oprations distinctes utilisant deux outils diffrents, contrairement
au monde DOS et Windows dans lequel cela ne correspond qu une seule opration effectue par un unique outil. Un fichier tarball est cr en combinant plusieurs fichiers et/ou rpertoires grce la commande tar (tape archive), puis compress laide
des outils compress, gzip ou bzip2 ; ce qui gnre des fichiers comme tarball.tar.Z, tarball.tar.gz, tarball.tgz ou tarball.tar.bz2. Cependant, de nombreux autres outils, tels que
zip, sont aussi supports.
Pour utiliser le format correct, vous devez savoir o et comment les donnes seront utilises. Si vous ne faites que compresser des fichiers pour vous-mme, utilisez ce qui vous
semble le plus simple. Si dautres personnes ont besoin de vos donnes, prenez aussi en
compte leur plateforme.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8.6. Compresser les fichiers

179

Historiquement, les tarball sous Unix taient compresss avec compress (tarball.tar.Z), mais gzip est maintenant bien plus rpandu et bzip2 (qui offre un meilleur
taux de compression que gzip) gagne du terrain. Une question doutil se pose galement.
Certaines versions de tar vous permettent dutiliser automatiquement la compression
de votre choix lors de la cration de larchive, dautres ne le permettent pas.
Le format universel accept par Unix ou Linux utilise gzip (tarball.tar.gz ou tarball.tgz) ;
il est cr comme ceci :
$ tar cf nom_du_tarball.tar rpertoire_de_fichiers
$ gzip nom_du_tarball.tar

Si vous disposez de la version GNU de tar, vous pourriez indiquer -Z pour utiliser compress (ne le faites pas, ce format est obsolte), -z pour recourir gzip (le choix le plus
sr) ou -j pour employer bzip2 (meilleure compression). Noubliez pas dutiliser un
nom de fichier cohrent avec le format de compression, ce nest pas automatique.
$ tar czf nom_du_tarball.tgz rpertoire_de_fichiers

Alors que tar et gzip sont disponibles sur de nombreuses plateformes, si vous devez partager vos donnes avec une plateforme Windows, vous devriez plutt utiliser zip, qui est
presque universel. zip et unzip sont fournis par le paquetage InfoZip sous Unix et presque toutes les plateformes pouvant vous venir lesprit. Malheureusement, ils ne sont
pas toujours installs par dfaut. Comme ces outils ne viennent pas du monde Unix,
pour obtenir des informations daide lutilisation lancez la commande sans argument
ni redirection. Notez la prsence de loption -l pour convertir les fins de ligne du format Unix au format Microsoft et loption -ll pour faire le contraire.
$ zip -r nom_du_fichier_zip rpertoire_de_fichiers

Discussion
Il existe de trop nombreux algorithmes et outils de compression pour tous les traiter ici ;
on peut citer : AR, ARC, ARJ, BIN, BZ2, CAB, CAB, JAR, CPIO, DEB, HQX, LHA, LZH,
RAR, RPM, UUE et ZOO.
Avec tar, nous vous recommandons fortement dutiliser des chemins relatifs comme argument pour lister les fichiers archiver. Si vous prenez un nom de rpertoire absolu,
vous pourriez craser involontairement quelque chose sur le systme utilis lors de la
dcompression et si vous nindiquez pas de rpertoire du tout, vous allez polluer le rpertoire courant dans lequel la commande de dcompression sera lance (voir la recette
8.8, page 182). Habituellement, il est recommand dutiliser le nom et ventuellement
la version des donnes archiver comme nom de rpertoire. Le tableau 8-2 donne quelques exemples.
Tableau 8-2. Bons et mauvais exemples pour nommer les rpertoires archiver avec tar
Bon

Mauvais

./monappli_1.0.1

monappli.c
monappli.h
monappli.man

./bintools

/usr/local/bin

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

180

Chapitre 8 Outils shell intermdiaires II

Il faut noter que les fichiers du gestionnaire de paquetages de Red Hat (Red Hat Package
Manager, RPM) sont en fait des fichiers CPIO avec un en-tte. Vous pouvez obtenir un
script shell ou Perl appel rpm2cpio (http://fedora.redhat.com/docs/drafts/rpm-guide-en/chextra-packaging-tools.html) pour liminer ces en-ttes et extraire les fichiers de larchive
ainsi :
$ rpm2cpio un.rpm | cpio -i

Les fichiers Debian .deb sont, quant eux, des archives ar contenant des archives tar
compresses avec gzip ou bzip2. Ils peuvent tre extraits avec les outils standard ar, tar et
gunzip ou bunzip2.
De nombreux outils sous Windows tels que WinZip, PKZIP, FilZip et 7-Zip peuvent grer tous les formats ci-dessus ou presque, voire mme dautres formats tels que .tar ou
.rpm.

Voir aussi

man tar ;

man gzip ;

man bzip2 ;

man compress ;

man zip ;

man rpm ;

man ar ;

man dpkg ;

http://www.info-zip.org/ ;

http://fedora.redhat.com/docs/drafts/rpm-guide-en/ch-extra-packaging-tools.html ;

http://en.wikipedia.org/wiki/Deb_(file_format) ;

http://www.rpm.org/ ;

http://en.wikipedia.org/wiki/RPM_Package_Manager ;

la recette 7.9, Rechercher dans les fichiers compresss, page 159 ;

la recette 8.7, Dcompresser des fichiers, page 180 ;

la recette 8.8, Vrifier les rpertoires contenus dans une archive tar, page 182 ;

la recette 17.3, Dzipper plusieurs archives ZIP, page 432.

8.7. Dcompresser des fichiers


Problme
Vous devez dcompresser un ou plusieurs fichiers portant une extension telle que tar,
tar.gz, gz, tgz, Z ou zip.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8.7. Dcompresser des fichiers

181

Solution
Dterminez le format des fichiers et utilisez loutil appropri. Le tableau 8-3 fait correspondre les extensions les plus courantes aux programmes capables de les manipuler.
Tableau 8-3. Extensions courantes et outils associs
Extensions des fichiers

Commandes

.tar

tar tf (liste le contenu), tar xf (extrait)

.tar.gz, .tgz

GNU tar : tar tzf (liste le contenu), tar xzf (extrait) ou :


gunzip fichier && tar xf fichier

.tar.bz2

GNU tar : tar tjf (liste le contenu), tar xjf (extrait) ou :


gunzip2 fichier && tar xf fichier

.tar.Z

GNU tar : tar tZf (liste le contenu), tar xZf (extrait) ou :


uncompress fichier && tar xf fichier

.zip

unzip (rarement install par dfaut)

Vous devriez aussi essayer la commande file :


$ file fichier_inconnu.*
fichier_inconnu.1: GNU tar archive
fichier_inconnu.2: gzip compressed data, from Unix
$ gunzip fichier_inconnu.2
gunzip: fichier_inconnu.2: unknown suffix -- ignored
$ mv fichier_inconnu.2 fichier_inconnu.2.gz
$ gunzip fichier_inconnu.2.gz
$ file fichier_inconnu.2
fichier_inconnu.2: GNU tar archive

Discussion
Si lextension ne correspond aucune de celles listes dans le tableau 8-3, que la commande file ne vous aide pas, mais que vous tes certain quil sagit bien dune archive,
vous devriez alors effectuer une recherche sur le Web.

Voir aussi

la recette 7.9, Rechercher dans les fichiers compresss, page 159 ;

la recette 8.6, Compresser les fichiers, page 178.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

182

Chapitre 8 Outils shell intermdiaires II

8.8. Vrifier les rpertoires contenus dans une


archive tar
Problme
Vous voulez dsarchiver une archive .tar, mais vous voulez dabord connatre les rpertoires dans lesquels elle va crire les fichiers. Vous pouvez consulter la table des matires
de larchive avec tar -t, mais le rsultat peut tre trs volumineux et il est facile de passer ct dune ligne importante.

Solution
Utilisez un script awk pour filtrer les noms des rpertoires partir de la table des matires de larchive tar, puis avec sort -u liminez les doublons :
$ tar tf archive.tar | awk -F/ '{print $1}' | sort -u

Discussion
Loption t affiche la table des matires du fichier dont le nom est indiqu par loption
f. La commande awk utilise un sparateur de champs non-standard laide de loption
-F/ (le caractre barre oblique). Ainsi, linstruction print $1 affichera le premier nom
de rpertoire du chemin.
Enfin, tous les noms de rpertoires seront tris et ne seront affichs quune seule fois.
Si une ligne de laffichage contient uniquement un simple point, cela signifie que certains fichiers seront extraits dans le rpertoire courant lorsque vous dcompresserez le
fichier tar, vrifiez donc que vous vous trouvez bien dans le rpertoire souhait.
De mme, si les noms des fichiers situs dans larchive sont tous locaux, sans ./ au dbut, vous obtiendrez la liste des noms de fichier qui seront crs dans le rpertoire courant.
Si laffichage contient une ligne vide, cela signifie que certains fichiers ont t archivs
partir dun chemin absolu (commenant par le caractre /). Une fois de plus, soyez
prudent lors de lextraction partir dune telle archive car vous pourriez craser des fichiers involontairement.

Voir aussi

man tar ;

man awk ;

la recette 8.1, Trier votre affichage, page 171 ;

la recette 8.2, Trier les nombres, page 172 ;

la recette 8.3, Trier des adresses IP, page 173.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8.9. Substituer des caractres

183

8.9. Substituer des caractres


Problme
Vous devez remplacer un caractre par un autre dans tout votre texte.

Solution
Utilisez la commande tr pour remplacer un caractre par un autre. Par exemple :
$ tr ';' ',' < fichier.avant > fichier.apres

Discussion
Dans sa forme la plus simple, une commande tr remplace les occurrences du premier
(uniquement) caractre du premier argument par le premier (uniquement) caractre
du second argument.
Dans lexemple de la solution, nous avons inject le contenu dun fichier appel fichier.avant dans le filtre, redirig la sortie vers un fichier appel fichier.apres et nous
avons remplac tous les points-virgules par des virgules.
Pourquoi utilisons-nous des apostrophes autour du point-virgule et de la virgule ? Un
point-virgule a une signification particulire pour le shell bash. Si nous ne le protgeons
pas, bash va linterprter comme un sparateur de commande et va considrer que la ligne comporte deux commandes, ce qui va entraner une erreur. La virgule na pas de
sens particulier, mais nous lavons protge par habitude pour viter toute interprtation laquelle nous naurions pas pense ; il est plus prudent dutiliser toujours des
apostrophes, ainsi on ne les oublie pas lorsquelles sont ncessaires.
La commande tr peut faire bien plus dune substitution la fois en plaant plusieurs
caractres traduire dans le premier argument et leurs caractres de substitution respectifs dans le second argument. Noubliez pas quil sagit toujours dun remplacement unpour-un. Par exemple :
$ tr ';:.!?' ',' < ponctuations.txt > virgules.txt

substituera une virgule tous les caractres de ponctuation rencontrs (point-virgule,


deux-points, point, point dexclamation et point dinterrogation). Comme le second argument est plus court que le premier, son dernier (et unique) caractre est rpt pour
que sa longueur soit gale celle du premier argument, ainsi chaque caractre remplacer correspond une virgule.
Ce type de transformation peut aussi tre effectu par la commande sed, cependant la
syntaxe de cette dernire est un peu plus complexe. La commande tr nest pas aussi puissante car elle ne reconnat pas les expressions rgulires mais elle dispose dune syntaxe
particulire pour les plages de caractres et cela peut savrer bien pratique comme nous
le verrons dans la recette 8.10, page 184.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

184

Chapitre 8 Outils shell intermdiaires II

Voir aussi

man tr.

8.10. Changer la casse des caractres


Problme
Vous devez liminer les diffrences de casse dans texte.

Solution
Vous pouvez convertir tous les caractres majuscules (A-Z) en minuscules (a-z) en utilisant la commande tr et en lui transmettant une plage de caractres comme le montre
lexemple suivant :
$ tr 'A-Z' 'a-z' < fichier_avec_majuscules.txt > fichier_sans_majuscules.txt

tr dispose aussi dune syntaxe particulire pour convertir ce type de plages :


$ tr '[:upper:]' '[:lower:]' < avec_majuscules.txt > sans_majuscules.txt

Discussion
Mme si la commande tr ne gre pas les expressions rgulires, elle prend en charge les
plages de caractres. Vrifiez bien que les deux arguments comportent le mme nombre
de caractres. Si le second argument est plus court, son dernier caractre sera rpt
autant de fois que ncessaire pour atteindre une longueur gale celle du premier. En
revanche, si le premier argument est le plus court, le second sera tronqu la mme
taille que le premier.
Voici un codage trs simpliste dun message textuel laide dun chiffrement par substitution qui dcale chaque caractre de treize places (connu sous le nom de ROT13).
Une des proprits intressantes de ROT13 est que le mme processus sert la fois chiffrer et dchiffrer le texte :
$ cat /tmp/plaisanterie
Q: Pourquoi le poulet a-t-il travers la route ?
R: Pour aller de l'autre ct.
$ tr 'A-Za-z' 'N-ZA-Mn-za-m' < /tmp/plaisanterie
D: Cbhedhbv yr cbhyrg n-g-vy geniref yn ebhgr ?
E: Cbhe nyyre qr y'nhger pg.
$ tr 'A-Za-z' 'N-ZA-Mn-za-m' < /tmp/plaisanterie | \
tr 'A-Za-z' 'N-ZA-Mn-za-m'
Q: Pourquoi le poulet a-t-il travers la route ?
R: Pour aller de l'autre ct.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8.11. Convertir les fichiers DOS au format Linux/Unix

185

Voir aussi

man tr ;

http://fr.wikipedia.org/wiki/ROT13.

8.11. Convertir les fichiers DOS au format


Linux/Unix
Problme
Vous devez convertir des fichiers texte du format DOS au format Linux ou Unix. Sous
DOS, chaque ligne se termine par un couple de caractres (retour-chariot et passage la
ligne). Sous Linux, chaque ligne se termine uniquement par le caractre de passage la
ligne. Comment donc effacer ces caractres DOS superflus ?

Solution
Utilisez loption -d de tr pour effacer les caractres fournis dans la liste. Par exemple,
pour supprimer tous les retours-chariot DOS (\r), saisissez la commande :
$ tr -d '\r' <fichier_dos.txt >fichier_unix.txt
Cela va supprimer tous les caractres \r du fichier, y compris ceux qui
ne sont pas la fin des lignes. Habituellement, les fichiers texte comportent rarement ailleurs de tels caractres, mais cela reste possible.
Vous pouvez aussi vous tourner vers les programmes dos2unix et
unix2dos si ce comportement vous drange.

Discussion
Loutil tr dispose de quelques squences dchappement parmi lesquelles on peut citer
\r pour les retours-chariot et \n pour les passages la ligne. Les autres squences spciales sont listes dans le tableau 8-4.
Tableau 8-4. Les squences d'chappement de l'outil tr
Squence

Signification

\ooo

Caractre dont la valeur octale est ooo

\\

Un caractre barre oblique inverse (chappement de la barre oblique


inverse elle-mme)

\a

Bip audible , le caractre ASCII BEL ( b est dj occup par la


suppression arrire)

\b

Suppression arrire (correction du dernier caractre)

\f

Saut de page

\n

Passage la ligne

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

186

Chapitre 8 Outils shell intermdiaires II

Tableau 8-4. Les squences d'chappement de l'outil tr


Squence

Signification

\r

Retour-chariot

\t

Tabulation horizontale

\v

Tabulation verticale

Voir aussi

man tr.

8.12. Supprimer les guillemets


Problme
Vous voulez obtenir un texte en ASCII pur partir dun document MS Word mais, lorsque vous le sauvegardez en tant que texte, certains caractres spciaux subsistent.

Solution
Convertir les caractres spciaux en caractres ASCII classiques :
$ tr '\221\222\223\224\226\227' '\047\047""--' < source.txt >
destination.txt

Discussion
De tels guillemets typographiques viennent du jeu de caractres Windows-1252 et
peuvent aussi apparatre dans des courriels enregistrs au format texte. Pour citer Wikipdia sur le sujet :
Quelques clients de messagerie envoient des guillemets en utilisant les codes Windows1252 mais ils indiquent que le texte est encod avec le jeu de caractres ISO-8859-1 ce qui
cause des problmes aux dcodeurs qui ne dduisent pas automatiquement que le code
de contrle C1 en ISO-8859-1 correspond en fait des caractres Windows-1252.

Pour nettoyer de tels textes, nous pouvons utiliser la commande tr. Les caractres guillemets (cods 221 et 222 en octal) seront convertis en apostrophes doubles (guillemets anglais prsents dans le jeu de caractres ASCII). Nous spcifions ces apostrophes doubles
en octal (047) pour des raisons de facilit car linterprteur de commande Unix utilise
les apostrophes comme dlimiteurs. Les codes 223 et 224 (octal) correspondent aux
guillemets ouvrants et fermants et seront convertis. Les caractres doubles apostrophes
peuvent tre saisis en second argument car les apostrophes les entourant les protgent
de toute interprtation par le shell. Les caractres 226 et 227 (octal) sont des tirets longs
et seront convertis en trait dunion (la seconde occurrence du trait dunion dans la ligne
de commande nest pas indispensable car tr rpte le dernier caractre pour complter
le second argument la mme longueur que le premier argument, mais il est prfrable
dtre exhaustif).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8.13. Compter les lignes, les mots ou les caractres dans un fichier

187

Voir aussi

man tr ;

http://en.wikipedia.org/wiki/Curved_quotes pour savoir tout ce quil faut et plus sur les


guillemets et les problmes quils posent (lien en anglais).

8.13. Compter les lignes, les mots ou les


caractres dans un fichier
Problme
Vous avez besoin de connatre le nombre de lignes, de mots ou de caractres prsents
dans un fichier donn.

Solution
Utilisez la commande wc (word count) associe awk.
Laffichage standard de wc ressemble ceci :
$ wc fichier_donnes
5
15
60 fichier_donnes
# Compte uniquement les lignes
$ wc -l fichier_donnes
5 fichier_donnes
# Compte uniquement les mots
$ wc -w fichier_donnes
15 fichier_donnes
# Compte uniquement les caractres (souvent gal au nombre d'octets)
$ wc -c fichier_donnes
60 fichier_donnes
# Taille du fichier en octets
$ ls -l fichier_donnes
-rw-r--r-- 1 jp users
60B Dec 6 03:18 fichier_donnes

Vous pourriez tre tent par une ligne comme celle-ci :


fichier_donnes_lines=$(wc -l "$fichier_donnes")

Elle ne fera pas ce que vous espriez, vous obtiendrez quelque chose du genre de 5
fichier_donnes comme rsultat. Essayez plutt :
fichier_donnes_lines=$(wc -l "$fichier_donnes" | awk '{print $1}')

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

188

Chapitre 8 Outils shell intermdiaires II

Discussion
Si votre version de wc est localise2, le nombre de caractres pourra tre diffrent du
nombre doctets, avec certains jeux de caractres.

Voir aussi

man wc ;

la recette 15.7, Dcouper lentre si ncessaire, page 345.

8.14. Reformater des paragraphes


Problme
Vous avez des textes dont certaines lignes sont trop longues ou trop courtes, vous aimeriez les reformater pour rendre le texte plus lisible.

Solution
Utilisez la commande fmt, ventuellement avec une longueur de ligne minimale et
maximale :
$ fmt texte
$ fmt 55 60 texte

Discussion
Une particularit de fmt est quelle sattend trouver des lignes vierges pour sparer les
en-ttes et les paragraphes. Si votre fichier ne contient pas ces lignes, il ny a aucun
moyen de diffrencier les changements de paragraphes des retours la ligne placs
lintrieur dun paragraphe. Vous obtiendrez donc un paragraphe gant dont la longueur des lignes sera homogne.
La commande pr peut aussi savrer intressante pour formater du texte.

Voir aussi

man fmt ;

man pr.

2. N.d.T. : elle prend en charge les paramtres spcifiques votre rgion gographique.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

8.15. Aller plus loin avec less

189

8.15. Aller plus loin avec less


less is more! 3

Problme
Vous aimeriez exploiter mieux les possibilits de lafficheur less.

Solution
Consultez la page de manuel de less et utilisez la variable $LESS et les fichiers ~/.lessfilter
et ~/.lesspipe.
less prend ses options partir de la variable $LESS alors, plutt que de crer un alias avec
vos options favorites, placez-les dans cette variable. Elle peut aussi bien contenir des options longues que courtes et des options passes en ligne de commande surchargent celles dclares dans la variable. Nous recommandons dutiliser les options longues dans
la variable $LESS car elles sont plus lisibles. Par exemple :
export LESS="--LONG-PROMPT --LINE-NUMBERS --ignore-case --QUIET"

Mais ce nest quun dbut. less est extensible grce aux prprocesseurs d'entre, qui ne sont
que de simples programmes ou scripts pour pr-traiter le fichier que less est sur le point
dafficher. Cette fonctionnalit est gre par les variables denvironnement $LESSOPEN
et $LESSCLOSE.
Vous pouvez construire votre propre prprocesseur, mais conomisez du temps et consultez le script lesspipe.sh de Wolfgang Friebel disponible sur http://www-zeuthen.desy.de/
~friebel/unix/lesspipe.html (mais commencez par lire la discussion ci-dessous). Le script
fonctionne en initialisant et en exportant la variable denvironnement $LESSOPEN lorsquil est excut seul :
$ ./lesspipe.sh
LESSOPEN="|./lesspipe.sh %s"
export LESSOPEN

Vous pouvez donc lexcuter simplement dans une instruction eval, telle que eval
$(/path/to/lessfilter.sh) ou eval `/path/ to/lessfilter.sh` avant dutiliser less
comme votre habitude. La liste des formats supports pour la version 1.53 est :
gzip, compress, bzip2, zip, rar, tar, nroff, archive ar, pdf, ps, dvi, bibliothques partages, programmes, rpertoires, RPM, Microsoft Word, formats OpenOffice 1.x et OASIS (OpenDocument), Debian, fichiers MP3, formats d'image (png, gif, jpeg, tiff, ...),
textes utf-16, images iso et des systmes de fichiers sur support amovible travers
/dev/xxx

Mais il souffre dun inconvnient : le traitement de ces formats ncessite diffrents


outils externes, les fonctionnalits de lexemple dutilisation de lesspipe.sh ne pourront

3. N.d.T. : loutil habituel pour afficher du texte est more , qui se traduit en franais par
plus . less , qui est une alternative more se traduit, quant lui par moins . Le jeu
de mot se traduit donc par moins est plus !

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

190

Chapitre 8 Outils shell intermdiaires II

pas toutes fonctionner si vous ne disposez pas des outils associs aux formats. Le paquetage contient aussi des scripts ./configure (ou make) pour gnrer une version spcifique
du filtre fonctionnant avec les outils disponibles sur votre systme.

Discussion
less est unique dans le sens quil sagit dun outil GNU qui tait dj install par dfaut
sur chaque systme de test que nous avons utilis, vraiment tous ! Mme bash nest pas
dans cette situation. En mettant les diffrences de version de ct, toutes les installations
fonctionnaient de la mme manire. Quel succs !
Cependant, nous ne pouvons pas en dire de mme pour lesspipe* et les filtres de less.
Nous avons trouv diffrentes versions, avec des fonctionnalits variables par rapport
celles dcrites ci-dessus.

Red Hat dispose dun /usr/bin/lesspipe.sh qui ne peut pas tre utilis avec cette syntaxe : eval `lesspipe`.

Debian offre un /usr/bin/lesspipe qui peut tre evalu et qui prend aussi en charge
des filtres supplmentaires grce un fichier ~/.lessfilter.

SUSE Linux dispose dun /usr/bin/lessopen.sh qui ne peut pas tre evalu.

FreeBSD propose un /usr/bin/lesspipe.sh rudimentaire (pas devaluation, de traitement des fichiers .Z, .gz ou .bz2).

Solaris, HP-UX, les autres BSD et Mac nen disposent pas du tout par dfaut.

Pour voir si vous avez dj de lune de ces versions, essayez ce qui suit sur votre systme.
Ce systme Debian propose lesspipe, mais il nest pas activ (la variable $LESSOPEN nest
pas dfinie) :
$ type lesspipe.sh; type lesspipe; set | grep LESS
-bash3: type: lesspipe.sh: not found
lesspipe is /usr/bin/lesspipe

Ce systme Ubuntu dispose du lesspipe Debian et il est utilis :


$ type lesspipe.sh; type lesspipe; set | grep LESS
-bash: type: lesspipe.sh: not found
lesspipe is hashed (/usr/bin/lesspipe)
LESSCLOSE='/usr/bin/lesspipe %s %s'
LESSOPEN='| /usr/bin/lesspipe %s'

Nous vous recommandons de tlcharger, configurer et dutiliser la version de lesspipe.sh crite par Wolfgang Friebel car cest la plus complte. Nous vous recommandons
aussi de consulter la page de manuel de less car elle est trs instructive.

Voir aussi

man less ;

man lesspipe ;

man lesspipe.sh ;

http://www.greenwoodsoftware.com/less/ ;

http://www-zeuthen.desy.de/~friebel/unix/lesspipe.html.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

9
Rechercher des fichiers
avec find, locate et slocate
Parvenez-vous retrouver facilement vos donnes dans tous vos systmes de fichiers ?
En gnral, il est assez facile de mmoriser les noms et les emplacements des premiers
fichiers crs. Ensuite, face laugmentation de leur nombre, vous crez des sous-rpertoires (ou dossiers) pour regrouper les fichiers connexes. Puis, des sous-rpertoires arrivent lintrieur des premiers sous-rpertoires et vous avez de plus en plus de mal
vous souvenir de lemplacement des donnes. Bien entendu, avec des disques durs de
plus en plus vastes, il est de moins en moins ncessaire de supprimer les fichiers devenus
obsoltes ou superflus.
Dans ce cas, comment pouvez-vous retrouver le fichier que vous avez modifi la semaine dernire ? Ou la pice jointe que vous avez enregistre dans un sous-rpertoire (dont
le choix tait pourtant logique ce moment-l) ? Votre systme de fichiers est peut-tre
encombr de fichiers MP3 stocks dans de nombreux dossiers.
Diffrents outils graphiques ont t dvelopps pour faciliter la recherche de fichiers.
Mais, comment pouvez employer le rsultat de ces recherches graphiques en entre
dautres commandes ?
bash et les outils GNU peuvent vous aider. Ils apportent des possibilits de recherche
tendues qui permettent de retrouver des fichiers en fonction de leur nom, de leur date
de cration ou de modification et mme de leur contenu. Ils envoient les rsultats sur
la sortie standard, ce qui convient parfaitement une utilisation dans dautres commandes ou scripts.
Ne vous inquitez plus, voici les informations dont vous avez besoin.

9.1. Retrouver tous vos fichiers MP3


Problme
Vous disposez dun grand nombre de fichiers audio MP3 parpills sur votre systme de
fichiers. Vous aimeriez les regrouper tous en un seul endroit afin de les organiser et de
les copier sur votre lecteur audio.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

192

Chapitre 9 Rechercher des fichiers avec find, locate et slocate

Solution
La commande find peut retrouver tous les fichiers, puis excuter une commande qui les
dplace au bon endroit. Par exemple :
$ find . -name '*.mp3' -print -exec mv '{}' ~/chansons \;

Discussion
La syntaxe de find ne ressemble pas celle des autres outils Unix. Les options ne sont
pas employes de manire classique, avec un tiret et un ensemble de lettres uniques suivies des arguments. la place, les options sont de courts mots donns dans une suite
logique qui dcrit la recherche des fichiers, puis le traitement leur appliquer, si ncessaire. Ces options, semblables des mots, sont souvent appeles prdicats.
Les premiers arguments de la commande find reprsentent les rpertoires dans lesquels
doit se faire la recherche. Vous indiquerez, en gnral, uniquement le rpertoire de travail (.). Mais vous pouvez donner une liste de rpertoires ou mme effectuer la recherche sur lintgralit du systme de fichiers (selon vos autorisations) en utilisant la racine
(/) comme point de dpart.
Dans notre exemple, la premire option (le prdicat -name) prcise le motif recherch.
Sa syntaxe est quivalente celle de la correspondance de motifs de bash. Par consquent, *.mp3 correspondra tous les noms de fichiers qui se terminent par les caractres
.mp3 . Tout fichier conforme ce motif donne le rsultat vrai et lexcution se poursuit avec le prdicat suivant de la commande.
Vous pouvez imaginer le processus de la manire suivante. find parcourt le systme de
fichiers et chaque nom de fichier trouv est prsent lensemble des conditions qui
doivent tre satisfaites. Lorsquune condition est remplie, la suivante est teste. Si une
condition nest pas remplie, le fichier est alors immdiatement cart et le suivant est
analys.
La condition -print est simple. Elle vaut toujours vrai et a pour effet dafficher le nom
du fichier sur la sortie standard. Par consquent, tout fichier ayant satisfait lensemble
des conditions prcdentes voit son nom affich.
Loption -exec est un peu plus trange. Lorsquun nom de fichier arrive jusqu elle, il
est insr dans une commande qui sera excute. La suite de la ligne, jusquaux caractres \;, constitue cette commande. Les accolades {} sont remplaces par le nom du fichier trouv. Par consquent, dans notre exemple, si find rencontre un fichier nomm
mhsr.mp3 dans le sous-rpertoire ./musique/jazz, la commande excute est alors :
mv ./musique/jazz/mhsr.mp3 ~/chansons

La commande concerne chaque fichier qui correspond au motif. Si le nombre de ces fichiers est trs grand, autant de commandes seront excutes. Parfois, cela ncessite des
ressources systme trop importantes. Il peut alors tre prfrable dutiliser find uniquement pour trouver les fichiers et de placer leur nom dans un fichier de donnes, puis
dexcuter dautres commandes en runissant plusieurs arguments sur une ligne. Cependant, les ordinateurs tant de plus en plus rapides, ce problme est de moins en
moins rel. Il se pourrait mme que votre processeur double ou quadruple cur ait
enfin de quoi soccuper.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

9.2. Traiter les noms de fichiers contenant des caractres tranges

193

Voir aussi

man find ;

la recette 1.3, Chercher et excuter des commandes, page 6 ;

la recette 1.4, Obtenir des informations sur des fichiers, page 8 ;

la recette 9.2, Traiter les noms de fichiers contenant des caractres tranges, page 193.

9.2. Traiter les noms de fichiers contenant des


caractres tranges
Problme
Vous utilisez une commande find comme celle de la recette 9.1, page 191, mais les rsultats ne sont pas ceux que vous attendiez car plusieurs fichiers ont des noms qui contiennent des caractres tranges.

Solution
Tout dabord, vous devez savoir que, pour les Unixiens, trange signifie tout ce qui
nest pas une lettre minuscule, voire un chiffre . Par consquent, les lettres majuscules,
les espaces, les symboles de ponctuation et les caractres accentus sont tous des caractres tranges. Nanmoins, ils apparaissent trs souvent dans les noms de chansons et
dartistes.
En fonction des caractres prsents dans les noms, de votre systme, de vos outils et de
votre objectif, il peut tre suffisant de placer la chane de remplacement entre apostrophes. Autrement dit, mettez des apostrophes autour de {} ('{}') .
Si cela ne change rien, utilisez largument -print0 de find et largument -0 de xargs.
-print0 indique find demployer le caractre nul (\0) et non lespace comme sparateur lors de laffichage des noms de chemins trouvs. -0 prcise ensuite xargs le sparateur de lentre. Cette solution fonctionne toujours, mais elle peut ne pas tre prise
en charge par votre systme.
La commande xargs prend des noms de chemins spars par des espaces (except lorsque
loption -0 est utilise) sur lentre standard et excute la commande indique pour le
plus grand nombre de noms possible (elle sarrte juste avant datteindre la valeur
ARG_MAX de votre systme ; voir la recette 15.13, page 357). Puisque linvocation dautres
commandes implique un surcot important, lutilisation de xargs permet dacclrer
lopration car les invocations de cette commande sont aussi rduites que possible (elle
nest pas appele pour chaque nom de chemin trouv).
Voici donc comment modifier la solution de la recette 9.1, page 191, pour prendre en
charge les caractres incongrus :
$ find . -name '*.mp3' -print0 | xargs -i -0 mv '{}' ~/chansons

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

194

Chapitre 9 Rechercher des fichiers avec find, locate et slocate

Voici un exemple similaire illustrant lutilisation de xargs pour la prise en charge des espaces dans les noms de chemins ou de fichiers lors de la localisation et de la copie de
fichiers :
$ locate P1100087.JPG PC220010.JPG PA310075.JPG PA310076.JPG | \
> xargs -i cp '{}' .

Discussion
Cette approche pose deux problmes. Premirement, il est possible que votre version
de xargs ne reconnaisse pas loption -i. Deuximement, loption -i interdit le regroupement des arguments et a donc un impact ngatif sur lamlioration des performances.
Le problme vient du fait que la commande mv attend le rpertoire cible en dernier argument, alors que la commande xargs classique prend simplement son entre et lajoute
la fin de la commande indique, jusqu ce quil ny ait plus de place ou que lentre
soit vide. Certaines versions de xargs offrent donc une option -i qui utilise par dfaut
{} (comme find). Cependant, -i impose que la commande soit excute individuellement pour chaque lment de lentre. Son seul avantage par rapport au prdicat -exec
de find rside dans la prise en charge des caractres tranges.
La commande xargs est, cependant, plus efficace lorsquelle est employe conjointement
find et une commande comme chmod, qui attend simplement la liste des arguments
traiter. Vous constaterez une nette amlioration des performances si vous manipulez un
grand nombre de noms de chemins. Par exemple :
$ find un_repertoire -type f -print0 | xargs -0 chmod 0644

Voir aussi

man find ;

man xargs ;

la recette 9.1, Retrouver tous vos fichiers MP3, page 191 ;

la recette 15.13, Contourner les erreurs liste darguments trop longue , page 357.

9.3. Acclrer le traitement des fichiers trouvs


Problme
Vous utilisez une commande find comme celle de la recette 9.1, page 191, mais le traitement des fichiers trouvs prend beaucoup de temps car ils sont nombreux. Vous souhaitez donc acclrer cette opration.

Solution
Consultez la prsentation de la commande xargs la recette 9.2, page 193.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

9.4. Suivre les liens symboliques

195

Voir aussi

la recette 9.1, Retrouver tous vos fichiers MP3, page 191 ;

la recette 9.2, Traiter les noms de fichiers contenant des caractres tranges, page 193.

9.4. Suivre les liens symboliques


Problme
Vous utilisez une commande find pour rechercher vos fichiers .mp3, mais elle ne les
trouve pas tous. Il manque ceux enregistrs dans un autre systme de fichiers et rfrencs par des liens symboliques. La commande find est-elle incapable de franchir ce type de
barrire ?

Solution
Utilisez le prdicat -follow. Notre exemple prcdent devient alors :
$ find . -follow -name '*.mp3' -print0 | xargs -i -0 mv '{}' ~/chansons

Discussion
Il arrive parfois que le passage dun systme de fichiers lautre ne soit pas voulu. Cest
pourquoi, par dfaut, la commande find ne suit pas les liens symboliques. Si vous souhaitez les prendre en compte, utilisez -follow en premire option de la commande
find.

Voir aussi

man find.

9.5. Retrouver des fichiers sans tenir compte de


la casse
Problme
Certains de vos fichiers MP3 se terminent par lextension .MP3 la place de .mp3. Comment pouvez-vous les inclure galement dans la recherche ?

Solution
Utilisez le prdicat -iname (si votre version de find le reconnat), la place de -name,
pour effectuer une recherche insensible la casse. Par exemple :
$ find . -follow -iname '*.mp3' -print0 | xargs -i -0 mv '{}' ~/chansons

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

196

Chapitre 9 Rechercher des fichiers avec find, locate et slocate

Discussion
La casse des noms de fichiers est parfois importante. Utilisez loption -iname lorsque ce
nest pas le cas, par exemple comme dans notre exemple o .mp3 et .MP3 dsignent tous
deux des fichiers trs probablement de type MP3. Nous prcisons probablement car, sur
les systmes de type Unix, vous pouvez nommer un fichier comme bon vous semble. Il
nest pas oblig de possder une extension prcise.
Le problme des lettres minuscules et majuscules est plus frquent lorsque vous manipulez des systmes de fichiers Microsoft Windows, notamment dun type ancien. Notre
appareil photo numrique enregistre ses fichiers avec des noms de la forme
PICT001.JPG, en incrmentant le nombre chaque image. La commande suivante trouvera peu dimages :
$ find . -name '*.jpg' -print

Dans ce cas, vous pouvez galement essayer la suivante :


$ find . -name '*.[Jj][Pp][Gg]' -print

En effet, lexpression rgulire trouvera une correspondance avec nimporte quelle lettre place entre les crochets. Cependant, cette forme de la commande est moins facile
saisir, en particulier si le motif est long. En pratique, -iname constitue une meilleure
solution. En revanche, toutes les versions de find ne prennent pas en charge ce prdicat. Si cest le cas de votre systme, vous pouvez toujours employer des expressions rgulires, utiliser plusieurs options -name avec des variantes de la casse ou installer la
version GNU de find.

Voir aussi

man find.

9.6. Retrouver des fichiers daprs une date


Problme
Supposez que vous ayez reu un fichier JPEG il y a plusieurs mois et que vous layez enregistr sur votre systme de fichiers, mais vous avez totalement oubli dans quel rpertoire. Comment pouvez-vous le retrouver ?

Solution
Utilisez une commande find avec le prdicat -mtime, qui vrifie la date de dernire modification. Par exemple :
find . -name '*.jpg' -mtime +90 -print

Discussion
Le prdicat -mtime attend un argument qui fixe la plage temporelle de la recherche. La
valeur 90 reprsente 90 jours. En ajoutant le signe plus au nombre (+90), vous indiquez
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

9.7. Retrouver des fichiers daprs leur type

197

que le fichier doit avoir t modifi il y a plus de 90 jours. En crivant -90 (avec un signe
moins), la modification doit avoir eu lieu il y a moins de 90 jours. Sans le signe plus ou
moins, la date de modification est exactement 90 jours.
Plusieurs prdicats permettent deffectuer la recherche en fonction de la date de modification dun fichier et chacun attend un argument de quantit. Un signe plus, un signe
moins ou aucun signe reprsente, respectivement, une date suprieure , infrieure
ou gale cette valeur.
find dispose galement des constructions logiques ET, OU et NON. Par consquent, si
vous savez que le fichier date dau moins une semaine (7 jours), mais pas plus de 14
jours, vous pouvez alors combiner les prdicats de la manire suivante :
$ find . -mtime +7 -a -mtime -14 -print

Des combinaisons plus complexes de OU, de ET et de NON sont mme possibles :


$ find . -mtime +14 -name '*.text' -o \( -mtime -14 -name '*.txt' \) -print

Cette commande affiche les fichiers dont le nom se termine par .text et qui datent de
plus de 14 jours, ainsi que les fichiers qui datent de moins de 14 jours et dont le nom se
termine par .txt.
Les parenthses seront sans doute ncessaires pour dfinir la priorit adquate. Deux
prdicats la suite quivalent un ET logique et sont prioritaires sur un OU (dans find
comme dans la plupart des langages). Utilisez les parenthses pour lever lambigut de
vos conditions.
Puisque les parenthses ont une signification particulire dans bash, vous devez les
chapper, en les crivant \( et \) ou avec des apostrophes, '(' et ')'. Cependant, vous
ne devez pas placer lintgralit de lexpression entre des apostrophes car cela perturbe
la commande find. Elle attend chacun de ses prdicats comme des mots spars.

Voir aussi

man find.

9.7. Retrouver des fichiers daprs leur type


Problme
Vous recherchez un rpertoire dont le contient le mot java . Vous essayez donc la
commande suivante
$ find . -name '*java*' -print

Elle trouve un grand nombre de fichiers, y compris les fichiers sources Java enregistrs
sur le systme de fichiers.

Solution
Utilisez le prdicat -type pour slectionner uniquement les rpertoires :
$ find . -type d -name '*java*' -print

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

198

Chapitre 9 Rechercher des fichiers avec find, locate et slocate

Discussion
Nous avons plac le prdicat -type d avant -name *java*. Lordre inverse produit le
mme ensemble de fichiers. Cependant, en commenant par -type d, la recherche sera
lgrement plus efficace car pour chaque fichier rencontr, la commande find commence par vrifier sil sagit dun rpertoire et, uniquement dans ce cas, compare son nom
au motif. Si tous les fichiers ont un nom, peu dentre eux sont des rpertoires. En choisissant cet ordre, la plupart des fichiers ne sont pas concerns par la comparaison de
chane. Est-ce vraiment un problme ? Les processeurs tant de plus en plus rapides, ce
point perd de limportance. Les disques durs tant de plus en plus volumineux, ce point
gagner de limportance. Le tableau 9-1 rcapitule les diffrents types de fichiers que vous
pouvez tester, en prcisant la lettre correspondante.
Tableau 9-1. Caractres utiliss par le prdicat -type de find
Lettre

Signification

Fichier spcial en mode bloc.

Fichier spcial en mode caractre.

Rpertoire.

Tube (ou fifo ).

Fichier normal.

Lien symbolique.

Socket.

(Solaris uniquement) door .

Voir aussi

man find.

9.8. Retrouver des fichiers daprs leur taille


Problme
Vous souhaitez faire un peu de mnage sur le disque dur, en commenant par trouver
les fichiers les plus volumineux et dcider si vous devez les supprimer ou non. Comment pouvez-vous retrouver ces fichiers ?

Solution
Utilisez le prdicat -size de la commande find pour slectionner les fichiers dont la
taille est suprieure, infrieure ou gale celle indique. Par exemple :
find . -size +3000k -print

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

9.9. Retrouver des fichiers daprs leur contenu

199

Discussion
Tout comme celui du prdicat -mtime, largument numrique de -size peut tre prcd dun signe moins, dun signe plus ou daucun signe, afin dindiquer une taille infrieure , suprieure ou gale largument. Dans notre exemple, nous recherchons les
fichiers dont la taille est suprieure celle prcise.
Nous avons galement indiqu une unit de taille, k pour kilo-octets. La lettre c dsigne
des octets (ou caractres). Si vous utilisez b, ou aucune unit, la taille correspond des
blocs. Un bloc quivaut 512 octets (une valeur courante sur les systmes Unix). Nous
recherchons donc des fichiers de taille suprieure 3 Mo.

Voir aussi

man find ;

man du.

9.9. Retrouver des fichiers daprs leur contenu


Problme
Comment pouvez-vous retrouver un fichier partir dun contenu dtermin ? Supposons que vous ayez crit une lettre importante et que vous layez enregistre sous forme
dun fichier texte, en lui donnant lextension .txt. En dehors de cela, vous savez uniquement que la lettre contient quelque part le mot prsage .

Solution
Si le fichier se trouve dans le rpertoire de travail, vous pouvez commencer par un simple grep :
grep -i prsage *.txt

Grce loption -i, grep ignore la casse. Cette commande ne permettra peut-tre pas de
trouver ce que vous recherchez, mais commenons simplement. Bien entendu, si vous
pensez que le fichier se trouve dans lun de vos nombreux sous-rpertoires, vous pouvez
tenter datteindre tous les fichiers contenus dans les sous-rpertoires du rpertoire courant laide de la commande suivante :
grep -i prsage */*.txt

Avouons-le, cette solution est assez limite.


Si elle ne convient pas, passez une solution plus labore, fonde sur la commande
find. Utilisez loption -exec de find afin dexcuter, si toutes les conditions sont vrifies,
une commande sur chaque fichier trouv. Voici comment invoquer grep ou nimporte
quel autre utilitaire :
find . -name '*.txt' -exec grep -Hi prsage '{}' \;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

200

Chapitre 9 Rechercher des fichiers avec find, locate et slocate

Discussion
Nous employons la construction -name '*.txt' pour rduire le champ de recherche.
Ce type de test conduit une meilleure efficacit, car lexcution dun programme spar pour chaque fichier trouv est trs coteuse en temps et en processeur. Vous avez
peut-tre galement une ide gnrale de lanciennet du fichier. Dans ce cas, servezvous galement du prdicat -mdate.
Lors de lexcution de la commande, '{}' est remplac par le nom de fichier. Les caractres \; indiquent la fin de la commande. Vous pouvez la faire suivre par dautres prdicats. Les accolades et le point-virgule doivent tre chapps. Nous plaons les
premires entre apostrophes et faisons prcder le second dune barre oblique inverse.
Lchappement choisi na pas dimportance, vous devez simplement viter que bash les
interprte de manire errone.
Sur certains systmes, loption -H affiche le nom du fichier uniquement si grep a trouv
quelque chose. Normalement, lorsquun seul nom de fichier lui est donn, grep ne sembte pas prsenter le nom du fichier, mais uniquement la ligne trouve. Puisque notre
recherche concerne de nombreux fichiers, il nous est important de connatre celui qui
contient la chane.
Si votre version de grep ne prend pas en charge loption -H, ajoutez simplement /dev/null
comme nom de fichier pass la commande grep. Puisquelle reoit ainsi plusieurs fichiers examiner, elle affiche le nom de celui qui contient la chane.

Voir aussi

man find.

9.10. Retrouver rapidement des fichiers ou du


contenu
Problme
Vous souhaitez pouvoir retrouver des fichiers sans avoir attendre la fin dune longue
commande find ou vous devez retrouver un fichier avec du contenu prcis.

Solution
Si votre systme dispose de locate, slocate, Beagle, Spotlight ou de tout autre systme
dindexation, vous tes par. Dans le cas contraire, installez-les.
Comme nous lavons expliqu la recette 1.3, page 6, locate et slocate consultent une base
de donnes stockant des informations sur le systme (gnralement compile et actualise par une tche cron) afin de trouver un fichier ou une commande quasi instantanment. Lemplacement de la base de donnes, les informations quelle contient et la
frquence dactualisation peuvent varier dun systme lautre. Pour plus de dtails,
consultez les pages de manuel de votre systme.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

9.10. Retrouver rapidement des fichiers ou du contenu

201

$ locate apropos
/usr/bin/apropos
/usr/share/man/de/man1/apropos.1.gz
/usr/share/man/es/man1/apropos.1.gz
/usr/share/man/it/man1/apropos.1.gz
/usr/share/man/ja/man1/apropos.1.gz
/usr/share/man/man1/apropos.1.gz

locate et slocate nindexent pas le contenu. Pour cela, voyez la recette 9.9, page 199.
Beagle et Spotlight sont des exemples dune technologie assez rcente appele moteur
de recherche locale. Google Desktop Search et Copernic Desktop Search en sont deux
exemples pour Microsoft Windows. Les outils de recherche locale emploient une forme
dindexation pour trouver, analyser et indexer les noms et le contenu de tous les fichiers
(et, en gnral, les messages lectroniques) de votre espace de stockage personnel ;
autrement dit, votre rpertoire personnel sur un systme Unix ou Linux. Ces informations sont disponibles presquinstantanment lorsque vous en avez besoin. Ces outils offrent de nombreuses possibilits de configuration et une interface graphique, oprent
de manire spcifique chaque utilisateur et indexent le contenu de vos fichiers.

Discussion
slocate mmorise les informations dautorisation (en plus des noms de fichiers et des
chemins) afin de ne pas prsenter les donnes auxquelles lutilisateur na pas accs. Sur
la plupart des systmes Linux, locate est un lien symbolique vers slocate. Dautres systmes peuvent disposer de programmes distincts ou omettre slocate. Ces deux outils en ligne de commande examinent et indexent lintgralit (plus ou moins) du systme de
fichiers, mais ne contiennent que des noms et des emplacements.

Voir aussi

man locate ;

man slocate ;

http://beagle-project.org/ ;

http://www.apple.com/fr/macosx/features/spotlight/ ;

http://desktop.google.fr/ ;

http://www.copernic.com/fr/products/desktop-search/ ;

la recette 1.3, Chercher et excuter des commandes, page 6 ;

la recette 9.9, Retrouver des fichiers daprs leur contenu, page 199.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

202

Chapitre 9 Rechercher des fichiers avec find, locate et slocate

9.11. Retrouver un fichier partir dune liste


demplacements possibles
Problme
Vous devez excuter ou lire un fichier, mais il peut se trouver en diffrents emplacements, inclus ou non dans votre variable $PATH.

Solution
Si vous voulez lire et excuter les commandes contenues dans un fichier qui se trouve
dans lun des rpertoires mentionn dans la variable $PATH, invoquez tout simplement
la commande source. Cette commande interne bash (galement connue sous le nom
POSIX plus court mais plus difficile lire . ) examine la variable $PATH si loption
sourcepath du shell est fixe, ce qui est le cas par dfaut :
$ source monFichier

Pour excuter un fichier uniquement sil existe dans la variable $PATH et quil est excutable, vous pouvez, avec bash version 2.05b ou ultrieure, utiliser la commande type -P
pour effectuer une recherche dans $PATH. Contrairement la commande which, type -P
affiche un rsultat uniquement si elle trouve le fichier. Elle est ainsi plus facile employer dans le cas suivant :
LS=$(type -P ls)
[ -x $LS ] && $LS
# --OU-LS=$(type -P ls)
if [ -x $LS ]; then
: commandes impliquant $LS
fi

Si la recherche doit se faire dans diffrents emplacements, y compris ou non ceux de


$PATH, utilisez une boucle for. Pour examiner le contenu de $PATH, servez-vous de loprateur de substitution de variables ${variable/motif/remplacement} afin de remplacer le
sparateur : par une espace et passer le rsultat une instruction for normale. Pour effectuer une recherche dans $PATH et dautres emplacements, il suffit de les indiquer :
for chemin in ${PATH//:/ }; do
[ -x "$chemin/ls" ] && $chemin/ls
done
# --OU-for chemin in ${PATH//:/ } /opt/foo/bin /opt/bar/bin; do
[ -x "$chemin/ls" ] && $chemin/ls
done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

9.11. Retrouver un fichier partir dune liste demplacements possibles

203

Si le fichier ne se trouve pas dans les rpertoires de $PATH, mais sil peut tre dans une
liste demplacements connus, prcisez les chemins et le nom complets :
for fichier in /usr/local/bin/inputrc /etc/inputrc ~/.inputrc; do
[ -f "$fichier" ] && bind -f "$fichier" && break # Utiliser le
# premier trouv.
done

Ajoutez tous les tests supplmentaires ncessaires. Par exemple, pour invoquer screen
lors de louverture de session uniquement si ce programme est prsent sur le systme,
procdez de la manire suivante :
for chemin in ${PATH//:/ }; do
if [ -x "$chemin/screen" ]; then
# Si screen(1) existe et est excutable :
for chemin in /opt/bin/settings/run_screen ~/settings/run_screen; do
[ -x "$chemin" ] && $chemin && break # Excuter le
# premier trouv.
done
fi
done

Consultez la recette 16.20, page 416, pour de plus amples informations sur ce code.

Discussion
Une boucle for pour parcourir chaque emplacement possible peut sembler quelque
peu exagre, mais cette solution savre trs souple. Elle permet deffectuer nimporte
quelle recherche, dappliquer tous les tests appropris et de manipuler le fichier trouv
comme bon vous semble. En remplaant : par une espace dans le contenu de $PATH,
nous obtenons une liste spare par des espaces telle que lattend for (mais, comme
nous lavons vu, toute liste spare par des espaces conviendra parfaitement). Vous pouvez adapter cette technique de manire crire des scripts shell trs souples, portables
et tolrants vis--vis de lemplacement dun fichier.
Vous pourriez tre tent de fixer la variable $IFS ':' pour analyser directement le
contenu de $PATH au lieu de le prparer dans $chemin. Cette solution fonctionne mais
demande un travail supplmentaire sur les variables et nest pas aussi souple.
Vous pourriez pensez crire une ligne telle que la suivante :
[ "$(which monFichier)" ] && bind -f $(which monFichier)

Dans ce cas, un problme se pose lorsque le fichier nexiste pas. La commande which se
comporte diffremment sur chaque systme. La version de Red Hat possde un alias
pour fournir des dtails supplmentaires lorsque largument est un alias et pour appliquer diffrentes options de la ligne de commande. Par ailleurs, elle retourne un message
indiquant que le fichier na pas t trouv (contrairement la version de which sur les
systmes Debian ou FreeBSD). Si vous excutez cette ligne sur NetBSD, la commande
bind reoit en argument la liste no monFichier in /sbin /usr/sbin /bin /usr/bin
/usr/pkg/sbin /usr/pkg/bin /usr/X11R6/bin /usr/local/sbin /usr/local/bin. Ce
nest pas vraiment ce que vous vouliez.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

204

Chapitre 9 Rechercher des fichiers avec find, locate et slocate

La commande command est galement intressante dans ce contexte. Elle existe depuis
plus longtemps que type -P et peut savrer utile dans certains cas.
Red Hat Enterprise Linux 4.x se comporte de la manire suivante :
$ alias which
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot
--show-tilde'
$ which rd
alias rd='rmdir'
/bin/rmdir
$ which ls
alias ls='ls --color=auto -F -h'
/bin/ls
$ which cat
/bin/cat
$ which cattt
/usr/bin/which: no cattt in
(/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/jp/bin
)
$ command -v rd
alias rd='rmdir'
$ command -v ls
alias ls='ls --color=auto -F -h'
$ command -v cat
/bin/cat

Sous Debian et FreeBSD (mais non NetBSD ou OpenBSD), le rsultat est lgrement
diffrent :
$ alias which
-bash3: alias: which: not found
$ which rd
$ which ls
/bin/ls
$ which cat
/bin/cat
$ which cattt
$ command -v rd
-bash: command: rd: not found

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

9.11. Retrouver un fichier partir dune liste demplacements possibles

205

$ command -v ls
/bin/ls
$ command -v cat
/bin/cat
$ command -v ll
alias ll='ls -l'

Voir aussi

help type ;

man which ;

help source ;

man source ;

la recette 16.20, Commencer une configuration personnalise, page 416 ;

la recette 17.4, Restaurer des sessions dconnectes avec screen, page 433.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

10
Autres fonctionnalits pour
les scripts
De nombreux scripts sont crits pour un objectif prcis et ne sont utiliss que par leur
auteur. Ils sont constitus de quelques lignes, voire mme dune seule boucle. En revanche, dautres scripts ont un dveloppement de niveau industriel et peuvent servir diffrents utilisateurs. Ce type de script doit souvent sappuyer sur des fonctionnalits qui
permettent un meilleur partage et rutilisation du code. Ces techniques labores de dveloppement bnficient diffrentes types de scripts et se retrouvent dans les systmes
de scripts plus vastes, comme le rpertoire /etc/init.d de nombreuses distributions Linux.
Mme sans tre administrateur systme, vous pouvez apprcier et employer ces techniques. Elles profiteront tout dveloppement de scripts un tant soit peu complexes.

10.1. Convertir un script en dmon


Problme
Vous souhaitez quun script sexcute comme un dmon, cest--dire en arrire-plan et
sans jamais sarrter. Pour que cela fonctionne, vous devez tre en mesure de dtacher
le script de son terminal de contrle (tty) qui a servi lancer le dmon. Placer une esperluette la fin de la commande ne suffit pas. Si vous lancez le script dmon sur un
systme distant via une session SSH (ou similaire), vous noterez que lors de la dconnexion, la session SSH ne se ferme pas et que la fentre reste bloque en lattente de la
terminaison du script (ce qui ne se produit pas puisquil est un dmon).

Solution
Utilisez la commande suivante pour invoquer le script, lexcuter en arrire-plan et garder la possibilit de fermer votre session :
nohup monScriptDemon 0<&- 1>/dev/null 2>&1

&

Ou bien :
nohup monScriptDemon >>/var/log/myadmin.log 2>&1
[05/03/08]

bash Le livre de recettes

<&- &

Elodie FRITSCH <elodie.fritsch@total.com>

208

Chapitre 10 Autres fonctionnalits pour les scripts

Discussion
Vous devez fermer le terminal de contrle (tty), qui est associ de trois manires toute
tche (dont la vtre) : par lentre standard (STDIN), par la sortie standard (STDOUT)
et par lerreur standard (STDERR). Pour fermer STDOUT et STDERR, vous pouvez les
rediriger vers un autre fichier, en gnral un fichier de journalisation, afin de pouvoir
examiner plus tard les rsultats du script, ou /dev/null, pour vous dbarrasser de la sortie
gnre. Dans notre exemple, nous utilisons pour cela loprateur de redirection >.
Mais, quen est-il de STDIN ? La solution la plus propre consiste fermer le descripteur
de fichier de STDIN. Avec la syntaxe de bash, cette opration ressemble une redirection, mais le nom de fichier est remplac par un tiret (0<&- ou <&-).
La commande nohup permet dexcuter le script sans quil soit interrompu par un signal
darrt lors de la fermeture de la session.
Dans le premier exemple, nous utilisons explicitement les numros de descripteur de
fichier (0, 1 et 2) dans les trois redirections. Puisquils sont facultatifs pour STDIN et
STDOUT, nous les avons omis dans le second exemple. Nous plaons galement la direction de lentre la fin de la deuxime commande plutt quau dbut, car lordre
nest pas important ici. En revanche, pour la redirection de STDERR, lordre est important et les numros de descripteur de fichier sont indispensables.

Voir aussi

les chapitres 2 et 3 pour plus dinformations sur la redirection de lentre et de la


sortie.

10.2. Rutiliser du code


Problme
Vous souhaitez que linitialisation de certaines variables du shell soit commune plusieurs scripts. Vous placez ces informations de configuration dans leur propre script.
Lorsque que vous excutez ce script partir dun autre, les valeurs ne sont pas conserves. Linitialisation est ralise dans un autre shell et, lorsque celui-ci disparat, vos valeurs disparaissent galement. Existe-t-il un moyen dexcuter ce script de configuration
au sein du shell courant ?

Solution
Utilisez la commande source du shell bash ou le point de POSIX (.) pour lire le contenu
du fichier de configuration. Les lignes de ce fichier sont traites comme si elles se trouvaient dans le script en cours.
Voici un exemple de donnes de configuration :
$ cat mesPrefs.cfg
REP_TEMP=/var/tmp

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

10.2. Rutiliser du code

209

FORMAT_IMAGE=png
FORMAT_AUDIO=ogg
$

Ce script simple est constitu de trois affectations. En voici un autre qui utilise ces valeurs :
#
# Utiliser les prfrences de lutilisateur.
#
source $HOME/mesPrefs.cfg
cd ${REP_TEMP:-/tmp}
echo Vous prfrez les fichiers dimage au format $FORMAT_IMAGE
echo Vous prfrez les fichiers audio au format $FORMAT_AUDIO

Discussion
Le script qui sappuie sur le fichier de configuration invoque la commande source pour
lire ce fichier. Vous pouvez galement remplacer le mot source par un point (.). Si le
point est plus facile et plus rapide saisir, il est galement plus difficile remarquer
dans un script ou une capture dcran :
. $HOME/mesPrefs.cfg

Vous ne serez pas le premier passer outre le point et penser que le script est tout simplement excut.
bash propose galement une troisime syntaxe issue du processeur dentre readline,
mais nous naborderons pas ce sujet ici. Sachez simplement que vous pouvez obtenir le
mme rsultat avec la commande suivante :
$include $HOME/mesPrefs.cfg

Le fichier doit se trouver dans votre chemin de recherche (ou inclure un chemin explicite), possder les droits dexcution et de lecture. Le symbole dollar ne reprsente pas
linvite de commande, mais fait partie de la directive $include.
La commande source est une fonctionnalit puissante et dangereuse. Elle vous permet
de crer un fichier de configuration et de le partager entre plusieurs scripts. Grce ce
mcanisme, vous pouvez ajuster la configuration en ne modifiant quun seul fichier.
Cependant, le contenu du fichier de configuration nest pas restreint des affectations
de variables. Toute commande shell valide est accepte. En effet, lorsque vous lisez un
fichier de cette manire, ses commandes sont interprtes par le shell bash. Quelles que
soient les commandes places dans le fichier lu, par exemple des boucles ou linvocation
dautres commandes, le shell les accepte et les excute comme si elles faisaient partie de
votre script.
Voici une version modifie du fichier de configuration :
$ cat mesPrefs.cfg
REP_TEMP=/var/tmp
FORMAT_IMAGE=$(cat $HOME/mesImages.pref)
if [ -e /media/mp3 ]
then
FORMAT_AUDIO=mp3

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

210

Chapitre 10 Autres fonctionnalits pour les scripts

else
FORMAT_AUDIO=ogg
fi
echo fichier de configuration charg
$

Il va un peu plus loin quune simple configuration de variables. Il excute une autre
commande (cat) et utilise une instruction if pour varier son droulement. Lorsque
vous utilisez la commande source, vous devez avoir conscience quelle reprsente une
porte grande ouverte dans votre script.
Cette approche est trs utile lorsque vous dfinissez des fonctions bash (voir la recette
10.3, page 210). En effet, ces fonctions peuvent alors tre partages comme une bibliothque commune tous les scripts qui lisent le script de dfinition des fonctions.

Voir aussi

la page de manuel de bash pour en savoir plus sur readline ;

la recette 10.3, Utiliser des fichiers de configuration dans un script, page 210 ;

la recette 10.4, Dfinir des fonctions, page 211.

10.3. Utiliser des fichiers de configuration dans


un script
Problme
Vous souhaitez disposer dun ou plusieurs fichiers de configuration pour un ou plusieurs scripts.

Solution
Vous pourriez crire un long code qui analyse un format propre aux fichiers de configuration, mais vitez cette approche. Transformez simplement le fichier de configuration en un script shell et utilisez la solution de la recette 10.2, page 208.

Discussion
Il sagit simplement dune application particulire de la lecture et de lexcution dun
fichier. Cependant, il vaut mieux rf lchir la manire dassurer que la configuration
correspond une syntaxe valide de bash. Vous pouvez, notamment, employer les indicateurs boolens et les variables facultatives (voir le chapitre 5, Variables du shell, et la
recette 15.11, page 354).
# Dans le fichier de configuration.
BAVARD=0
# '' pour inactif, 1 pour actif.
UTILISATEUR_SSH='jbagadonutz@' # Noter le @ la fin, mettre '' pour
# lutilisateur actuel.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

10.4. Dfinir des fonctions

211

# Dans le script.
[ "$BAVARD" ] || echo "Les messages de $) vont sur STDERR" >&2
[...]
ssh $UTILISATEUR_SSH$HOTE_DISTANT [...]

Cet exemple suppose que lutilisateur va lire les commentaires du script et crire ainsi
des instructions de configuration valides. Cette hypothse nest pas vraiment fiable. Par
consquent, au lieu de lui demander de consulter les notes et dajouter le caractre @ de
fin, vous pourriez complter le script par les lignes suivantes :
# Si $UTILISATEUR_SSH est fixe et ne contient pas le @ final, lajouter :
[ -n "$UTILISATEUR_SSH" -a "$UTILISATEUR_SSH" = "${UTILISATEUR_SSH%@}" ] &&
UTILISATEUR_SSH="$UTILISATEUR_SSH@"

Ou, plus simplement, en oprant directement la substitution :


ssh ${UTILISATEUR_SSH:+${UTILISATEUR_SSH}@}${HOTE_DISTANT} [...]

Loprateur :+ de bash fonctionne de la manire suivante. Si $UTILISATEUR_SSH contient


une valeur, il retourne la valeur sa droite (dans ce cas, nous avons indiqu la variable
elle-mme avec un @ supplmentaire). Si aucune valeur ne lui a t affecte ou si elle est
vide, il ne retourne rien.

Voir aussi

le chapitre 5 ;

la recette 10.2, Rutiliser du code, page 208 ;

la recette 15.11, Obtenir lentre depuis une autre machine, page 354.

10.4. Dfinir des fonctions


Problme
plusieurs endroits de votre script, vous aimeriez fournir lutilisateur un message
dutilisation (un message qui dcrit la bonne syntaxe de la commande), mais vous ne
voulez pas reproduire plusieurs fois la mme instruction echo. Si vous placez le message
dutilisation dans son propre script, vous pouvez linvoquer depuis nimporte quel endroit du script dorigine, mais il faut alors deux scripts. Existe-t-il un meilleur moyen
dcrire le code une fois et de le rutiliser par la suite ?

Solution
Utilisez une fonction bash. Au dbut du script, ajoutez du code similaire au suivant :
function utilisation ()
{
printf "usage : %s [ -a | - b ]
}

[05/03/08]

bash Le livre de recettes

fichier1 ... fichiern\n" $0

> &2

Elodie FRITSCH <elodie.fritsch@total.com>

212

Chapitre 10 Autres fonctionnalits pour les scripts

Puis, diffrents endroits du script, vous pouvez invoquer la fonction qui affiche le message dutilisation :
if [ $# -lt 1]
then
utilisation
fi

Discussion
Il existe diffrentes manires de dfinir des fonctions ([ function ] nom () commandecombine [ redirections ]). Voici plusieurs variantes de la dfinition dune fonction :
function utilisation ()
{
printf "usage : %s [ -a | - b ]
}

function utilisation {
printf "usage : %s [ -a | - b ]
}

usage ()
{
printf "usage : %s [ -a | - b ]
}

utilisation () {
printf "usage : %s [ -a | - b ]
}

fichier1 ... fichiern\n" $0

> &2

fichier1 ... fichiern\n" $0

> &2

fichier1 ... fichiern\n" $0

> &2

fichier1 ... fichiern\n" $0

> &2

Il faut au moins le mot rserv function ou la construction () finale. Si function est


utilis, les parenthses () sont facultatives. Nous prfrons employer le mot function car
il a lavantage dtre clair et lisible. Par ailleurs, il est facile rechercher. Par exemple,
grep '^function' script affiche la liste des fonctions du script.
La dfinition dune fonction doit se trouver au dbut du script shell, tout au moins
avant lendroit o elle est invoque. Elle nest, en un sens, quune instruction bash normale. Cependant, une fois excute, la fonction est alors dfinie. Si vous invoquez la
fonction avant de lavoir dfinie, vous recevrez une erreur du type commande non
trouve . Cest pour cette raison que nous plaons toujours nos dfinitions de fonctions avant toute autre commande du script.
Notre fonction contient simplement une instruction printf. Puisquil ny a quun seul
message dutilisation afficher, nous navons pas modifier plusieurs instructions en
cas, par exemple, dajout dune nouvelle option notre script.
Outre la chane de format, le seul argument de printf est $0, cest--dire le nom dinvocation du script shell. Vous pouvez galement employer lexpression $(basename $0)
afin que seule la dernire partie du nom de chemin soit incluse.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

10.5. Utiliser des fonctions : paramtres et valeur de retour

213

Puisque le message dutilisation constitue un message derreur, nous redirigeons la sortie de printf vers lerreur standard. Cette redirection peut tre place aprs la dfinition
de la fonction afin que toute sortie quelle peut produire soit galement redirige :
function utilisation ()
{
printf "usage : %s [ -a | - b ]

fichier1 ... fichiern\n" $0

} > &2

Voir aussi

la recette 7.1, Rechercher une chane dans des fichiers, page 150 ;

la recette 16.13, Concevoir une meilleure commande cd, page 396 ;

la recette 16.14, Crer un nouveau rpertoire et y aller avec une seule commande, page
398 ;

la recette 19.14, viter les erreurs commande non trouve avec les fonctions, page
502.

10.5. Utiliser des fonctions : paramtres et


valeur de retour
Problme
Vous souhaitez utiliser une fonction, mais vous avez besoin de lui passer quelques valeurs. Comment pouvez-vous dfinir des paramtres la fonction ? Comment pouvezvous obtenir des valeurs en retour ?

Solution
Vous ne devez pas ajouter de parenthses autour des arguments, comme cest le cas dans
dautres langages de programmation. Les paramtres dune fonction bash sont ajouts
directement aprs le nom de la fonction, spars par des espaces, comme pour linvocation dun script shell ou dune commande. Noubliez pas les guillemets, si ncessaire !
# Dfinir la fonction :
function max ()
{ ... }
#
# Appeler la fonction :
#
max 128 $SIM
max $VAR $TOTAL

Il existe deux manires de retourner des valeurs dune fonction. Vous pouvez les affecter
des variables lintrieur du corps de la fonction. Elles seront globales au script, sauf
si vous les dclarez explicitement locales (avec local) la fonction :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

214

Chapitre 10 Autres fonctionnalits pour les scripts

# bash Le livre de recettes : fonction_max.1


# Dfinir la fonction :
function max ()
{
local TEMPO
if [ $1 -gt $2 ]
then
PLUS_GRAND=$1
else
PLUS_GRAND=$2
fi
TEMPO=5
}

Par exemple :
# Appeler la fonction :
max 128 $SIM
# Utiliser le rsultat :
echo $PLUS_GRAND

Lautre solution sappuie sur les commandes echo ou printf pour afficher le rsultat sur
la sortie standard. Dans ce cas, linvocation de la fonction doit se faire lintrieur dune
construction $( ), en capturant la sortie et en utilisant le rsultat, ou bien il sera perdu
sur lcran :
# bash Le livre de recettes : fonction_max.2
# Dfinir la fonction :
function max ()
{
if [ $1 -gt $2 ]
then
echo $1
else
echo $2
fi
}

Par exemple :
# Appeler la fonction :
PLUS_GRAND=$(max 128
# Utiliser le rsultat
echo $PLUS_GRAND

$SIM)

Discussion
En ajoutant des paramtres dans linvocation de la fonction, elle ressemble un appel
de script shell. Les paramtres sont simplement des mots sur la ligne de commande.
Dans la fonction, les rfrences aux paramtres se font comme pour les arguments de la
ligne de commande, cest--dire avec $1, $2, etc. En revanche, $0 nest pas affect. Il con-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

10.6. Intercepter les signaux

215

serve toujours le nom dinvocation du script. Au retour de la fonction, $1, $2, etc. contiennent nouveau les paramtres dappel du script.
Nous devons galement mentionner le tableau $FUNCNAME. $FUNCNAME est en lui-mme
une rfrence llment zro du tableau, qui contient le nom de la fonction en cours
dexcution. Autrement dit, $FUNCNAME est aux fonctions ce que $0 est aux scripts, lexception de linformation de chemin. Les autres lments du tableau constituent une
pile des appels, avec lappel principal en dernier lment. Cette variable nexiste que
pendant lexcution dune fonction.
$TEMPO illustre simplement la porte locale dune variable. Mme si nous pouvons lui
affecter une valeur lintrieur de la fonction, cette valeur nest plus disponible dans les
autres parties du script. Il sagit dune variable dont la valeur est locale la fonction. Elle
dbute son existence lors de lappel la fonction et disparat lorsque la fonction se termine.
Le retour de valeur au travers de variables est plus efficace et permet de grer un grand
nombre de donnes (autant de variables que ncessaire), mais cette approche a ses inconvnients. Elle oblige la fonction et les autres parties du script saccorder sur les
noms des variables. Cette forme de couplage conduit des problmes de maintenance.
La deuxime approche, qui utilise la sortie pour envoyer des valeurs, allge ce couplage,
mais son utilit est limite. En effet, le script doit faire beaucoup defforts pour analyser
le rsultat de la fonction. Le choix entre ces deux mthodes est, comme toujours, une
question de compromis et de besoins prcis.

Voir aussi

la recette 1.6, Protger la ligne de commande, page 12 ;

la recette 16.4, Modifier temporairement $PATH, page 377.

10.6. Intercepter les signaux


Problme
Vous souhaitez crire un script qui intercepte les signaux et apporte une rponse adquate.

Solution
Utilisez trap pour dfinir des gestionnaires de signaux. Premirement, excutez trap -l
(ou kill -l) pour obtenir la listes des signaux disponibles. Elle varie dun systme
lautre :
# NetBSD
$ trap -l
1) SIGHUP
5) SIGTRAP
9) SIGKILL
13) SIGPIPE

[05/03/08]

bash Le livre de recettes

2)
6)
10)
14)

SIGINT
SIGABRT
SIGBUS
SIGALRM

3)
7)
11)
15)

SIGQUIT
SIGEMT
SIGSEGV
SIGTERM

4)
8)
12)
16)

SIGILL
SIGFPE
SIGSYS
SIGURG

Elodie FRITSCH <elodie.fritsch@total.com>

216
17)
21)
25)
29)

Chapitre 10 Autres fonctionnalits pour les scripts


SIGSTOP
SIGTTIN
SIGXFSZ
SIGINFO

18)
22)
26)
30)

SIGTSTP
SIGTTOU
SIGVTALRM
SIGUSR1

19)
23)
27)
31)

SIGCONT
SIGIO
SIGPROF
SIGUSR2

20)
24)
28)
32)

SIGCHLD
SIGXCPU
SIGWINCH
SIGPWR

# Linux
$ trap -l
1) SIGHUP
5) SIGTRAP
9) SIGKILL
13) SIGPIPE
18) SIGCONT
22) SIGTTOU
26) SIGVTALRM
30) SIGPWR
35) SIGRTMIN+2
39) SIGRTMIN+6
43) SIGRTMIN+10
47) SIGRTMIN+14
51) SIGRTMAX-13
55) SIGRTMAX-9
59) SIGRTMAX-5
63) SIGRTMAX-1

2)
6)
10)
14)
19)
23)
27)
31)
36)
40)
44)
48)
52)
56)
60)
64)

SIGINT
SIGABRT
SIGUSR1
SIGALRM
SIGSTOP
SIGURG
SIGPROF
SIGSYS
SIGRTMIN+3
SIGRTMIN+7
SIGRTMIN+11
SIGRTMIN+15
SIGRTMAX-12
SIGRTMAX-8
SIGRTMAX-4
SIGRTMAX

3)
7)
11)
15)
20)
24)
28)
33)
37)
41)
45)
49)
53)
57)
61)

SIGQUIT
SIGBUS
SIGSEGV
SIGTERM
SIGTSTP
SIGXCPU
SIGWINCH
SIGRTMIN
SIGRTMIN+4
SIGRTMIN+8
SIGRTMIN+12
SIGRTMAX-15
SIGRTMAX-11
SIGRTMAX-7
SIGRTMAX-3

4)
8)
12)
17)
21)
25)
29)
34)
38)
42)
46)
50)
54)
58)
62)

SIGILL
SIGFPE
SIGUSR2
SIGCHLD
SIGTTIN
SIGXFSZ
SIGIO
SIGRTMIN+1
SIGRTMIN+5
SIGRTMIN+9
SIGRTMIN+13
SIGRTMAX-14
SIGRTMAX-10
SIGRTMAX-6
SIGRTMAX-2

Ensuite, dfinissez vos gestionnaires de signaux. Notez que le code de retour de votre
script sera 128+numro de signal si la commande sest termine par le signal de ce numro.
Voici un cas simple dans lequel seule la rception dun signal, quel quil soit, nous intresse. Si nous avions utilis uniquement trap '' ABRT EXIT HUP INT TERM QUIT, ce script
aurait t trs difficile tuer car tous ces signaux seraient simplement ignors.
$ cat dur_a_tuer
#!/bin/bash trap ' echo "Je suis mort ! $?" ' ABRT EXIT HUP INT TERM QUIT
trap ' echo "Plus tard... $?"; exit ' USR1
sleep 120
$ ./dur_a_tuer
^Je suis mort ! 130
Je suis mort ! 130
$ ./dur_a_tuer &
[1] 26354
$ kill -USR1 %1
Signal #1 dfini par lusager
Plus tard... 158
Je suis mort ! 0
[1]+ Done
./dur_a_tuer
$ ./dur_a_tuer &
[1] 28180

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

10.6. Intercepter les signaux

217

$ kill %1
Je suis mort ! 0
[1]+ Terminated

./dur_a_tuer

Voici un exemple plus intressant :


#!/usr/bin/env bash
# bash Le livre de recettes : dur_a_tuer
function intercepte {
if [ "$1" = "USR1" ]; then
echo "Tu m'as eu avec un signal $1 !"
exit
else
echo "J'ai vit ton signal $1 -- nah nah nre"
fi
}
trap
trap
trap
trap
trap
trap
trap
trap

"intercepte
"intercepte
"intercepte
"intercepte
"intercepte
"intercepte
"intercepte
"intercepte

ABRT"
EXIT"
HUP"
INT"
KILL"
QUIT"
TERM"
USR1"

ABRT
EXIT
HUP
INT
KILL
QUIT
TERM
USR1

# Celui-ci ne fonctionne pas.

# Celui-ci est particulier.

# Attendre sans rien faire, sans introduire un comportement annexe


# avec les signaux, par exemple en utilisant 'sleep'.
while (( 1 )); do
:
# : est une instruction qui ne fait rien.
done

Nous invoquons le script prcdent et essayons de le tuer :


$ ./dur_a_tuer
^CJ'ai vit ton signal -- nah nah nre
^CJ'ai vit ton signal -- nah nah nre
^CJ'ai vit ton signal -- nah nah nre
^Z
[1]+ Stopped
./dur_a_tuer
$ kill -TERM %1
[1]+ Stopped
./dur_a_tuer
J'ai vit ton signal TERM -- nah nah nre
$ jobs
[1]+ Stopped

./dur_a_tuer

$ bg
[1]+ ./dur_a_tuer &

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

218
$ jobs
[1]+ Running

Chapitre 10 Autres fonctionnalits pour les scripts

./dur_a_tuer &

$ kill -TERM %1
J'ai vit ton signal TERM -- nah nah nre
$ kill -HUP %1
J'ai vit ton signal HUP -- nah nah nre
$ kill -USR1 %1
Tu m'as eu avec un signal USR1 !
J'ai vit ton signal EXIT -- nah nah nre
[1]+ Done

./dur_a_tuer

Discussion
Tout dabord, vous devez savoir quil est impossible dintercepter le signal -SIGKILL
(-9). Ce signal tue immdiatement les processus, sans que vous puissiez vous y opposer.
Nos exemples ntaient donc pas rellement difficiles tuer. Cependant, noubliez pas
que ce signal ne permet pas au script ou au programme de sarrter proprement, en faisant le mnage. Ce fonctionnement est gnralement dconseill et vous devez donc
viter dutiliser kill -KILL, moins de navoir dautres solutions.
trap semploie de la manire suivante :
trap [-lp] [arg] [signal [signal]]

Le premier argument, en dehors des options, indique trap le code excuter lorsque
le signal prcis est reu. Comme vous lavez vu prcdemment, le code complet peut
se trouver dans cet argument ou faire appel une fonction. Ds quil devient un tantinet
complexe, il est prfrable dutiliser une ou plusieurs fonctions de traitement, puisque
cela permet galement une terminaison propre. Si largument est une chane vide, le ou
les signaux indiqus sont ignors. Si largument est - ou sil est absent, alors quun ou
plusieurs signaux sont donns, ceux-ci sont rinitialiss leur traitement par dfaut du
shell. -l affiche la liste des noms de signaux, comme nous lavons vu prcdemment,
tandis que -p affiche les signaux courants et leurs gestionnaires.
Si vous utilisez plusieurs gestionnaires de signaux, nous vous conseillons de trier par ordre alphabtique les noms des signaux car la lecture et la maintenance en sont alors facilites.
Comme nous lavons signal, le code de sortie du script sera 128+numro de signal si la
commande se termine pas le signal de numro indiqu.
Il existe trois pseudo signaux jouant un rle particulier. Le signal DEBUG est similaire
EXIT mais il est utilis avant chaque commande des fins de dbogage. Le signal RETURN
est dclench lorsque lexcution reprend aprs un appel une fonction ou source (.).
Le signal ERR apparat lorsquune commande choue. Consultez le manuel de rfrence
de bash pour des informations dtailles et des mises en garde, notamment propos des
fonctions qui utilisent la commande interne declare ou loption set -o functrace.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

10.7. Redfinir des commandes avec des alias

219

Vous devez savoir que POSIX conduit des diffrences dans le fonctionnement de trap. Comme le note le manuel de rfrence, le lancement de bash avec loption de ligne de commande --posix ou linvocation de set -o posix pendant que bash est en cours dexcution
conduit un fonctionnement de bash plus conforme la norme POSIX
1003.2, notamment en modifiant son comportement dans les domaines o il diffre par dfaut des spcifications POSIX . Plus prcisment, les commandes kill et trap affichent alors uniquement les noms
de signaux sans le prfixe SIG et la sortie de kill -l est diffrente. Par
ailleurs, trap gre alors ses arguments de manire plus stricte, notamment en imposant un - initial pour rinitialiser les signaux leur traitement par dfaut du shell. Autrement dit, vous devez utiliser trap
-USR1 et non simplement trap USR1. Nous vous conseillons dinclure
systmatiquement le -, mme si ce nest pas ncessaire, car cela permet
de clarifier les objectifs du code.

Voir aussi

help trap ;

la recette 1.16, Documentation de bash, page 26 ;

la recette 10.1, Convertir un script en dmon, page 207 ;

la recette 14.11, Utiliser des fichiers temporaires scuriss, page 304 ;

la recette 17.7, Effacer lcran lorsque vous vous dconnectez, page 438.

10.7. Redfinir des commandes avec des alias


Problme
Vous souhaitez modifier lgrement la dfinition dune commande, peut-tre pour inclure systmatiquement une option prcise (par exemple, toujours utiliser loption -a
avec la commande ls ou -i avec rm).

Solution
Utilisez les alias de bash pour les shells interactifs (uniquement). La commande alias est
suffisamment intelligente pour ne pas entrer dans une boucle infinie lorsque vous dfinissez lalias comme le suivant :
alias ls='ls -a'

En saisissant simplement alias, sans autres arguments, vous obtenez la liste des alias
dfinis par dfaut dans la session bash. Sur certaines distributions, il est possible que les
alias que vous cherchez dfinir le soit dj.

Discussion
Les alias fonctionnent par un remplacement direct du texte. Cette substitution se produit au tout dbut du traitement de la ligne de commande et toutes les autres substitu-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

220

Chapitre 10 Autres fonctionnalits pour les scripts

tions se font ensuite. Par exemple, si vous voulez que la lettre h soit un alias dune
commande qui affiche le contenu de votre rpertoire personnel, saisissez la dfinition
suivante :
alias h='ls $HOME'

Ou bien celle-ci :
alias h='ls ~'

Les apostrophes sont significatives dans la premire version, pour que la variable $HOME
ne soit pas value lors de la dfinition de lalias. Ce nest que lors de lexcution de la
commande que la substitution doit tre ralise et que la variable $HOME doit tre value. Si, par la suite, vous modifiez la dfinition de $HOME, lalias en tiendra compte.
En remplaant les apostrophes par des guillemets, la substitution de la valeur de la variable se fait immdiatement et lalias contient la valeur de $HOME au moment de sa dfinition. Vous pouvez le constater en saisissant alias sans argument. bash affiche alors
toutes les dfinitions dalias, notamment la suivante :
...
alias h='ls /home/votreCompte'
...

Si les dfinitions de certains alias ne vous plaisent pas, vous pouvez les supprimer avec
la commande unalias et le nom de lalias concern. Par exemple :
unalias h

Cette commande supprime notre dfinition prcdente. unalias -a retire toutes les dfinitions dalias dans la session du shell en cours. Et si quelquun avait cr un alias pour
unalias ? La solution est trs simple. Il suffit de prfixer la commande par une barre oblique inverse et le dveloppement de lalias nest pas effectu : \unalias -a.
Les alias nacceptent pas les arguments. Par exemple, la ligne suivante est invalide :
# Ne fonctionne PAS car les arguments ne sont PAS autoriss.
$ alias='mkdir $1 && cd $1'

Les variables $1 et $HOME sont diffrentes car $HOME est dj dfinie (dune manire ou
dune autre) lorsque lalias est lui-mme dfini, alors que $1 est suppos arriver lors de
lexcution. Pour contourner ce problme, utilisez une fonction.

Voir aussi

lannexe C, Analyse de la ligne de commande, page 569, pour plus dinformations sur
le traitement de la ligne de commande ;

la recette 10.4, Dfinir des fonctions, page 211 ;

la recette 10.5, Utiliser des fonctions : paramtres et valeur de retour, page 213 ;

la recette 14.4, Effacer tous les alias, page 296 ;

la recette 16.14, Crer un nouveau rpertoire et y aller avec une seule commande, page
398.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

10.8. Passer outre les alias ou les fonctions

221

10.8. Passer outre les alias ou les fonctions


Problme
Vous avez crit un alias ou une fonction pour remplacer une commande, mais vous souhaitez prsent excuter la version relle.

Solution
Utilisez la commande interne builtin de bash. Elle permet dignorer les fonctions et les
alias du shell de manire excuter les commandes internes relles. La commande
command joue le mme rle, mais pour les commandes externes.
Si vous souhaitez contourner uniquement le dveloppement des alias, tout en gardant
les dfinitions de fonctions, prfixez la commande par une barre oblique inverse (\).
Servez-vous de la commande type (avec -a) pour savoir ce que vous faites.
Voici quelques exemples :
$ alias echo='echo ~~~'
$ echo test
~~~ test
$ \echo test
test
$ builtin echo test
test
$ type echo
echo is aliased to `echo ~~~'
$ unalias echo
$ type echo
echo is a shell builtin
$ type -a echo
echo is a shell builtin
echo is /bin/echo
$ echo test
test

Voici la dfinition dune fonction qui mritera quelques explications :


function cd ()
{
if [[ $1 = "..." ]]
then
builtin cd ../..

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

222

Chapitre 10 Autres fonctionnalits pour les scripts


else
builtin cd $1
fi

Discussion
La commande alias est suffisamment labore pour ne pas entrer dans une boucle infinie lorsque crivez des dfinitions du type alias ls='ls -a' ou alias echo='echo ~~~'.
Dans notre premier exemple, nous navons donc pas besoin dune syntaxe particulire
sur le ct droit de la dfinition de lalias pour faire rfrence la commande echo relle.
Lorsquun alias decho existe, la commande type nous indique non seulement quil sagit
bien dun alias mais nous en montre galement la dfinition. De manire similaire, pour
des dfinitions de fonctions, cette commande affichera le corps de la fonction. type -a
une_commande affiche tout (alias, commandes internes, fonctions et programmes externes)
ce qui contient une_commande (except lorsque loption -p est galement prsente).
Dans notre dernier exemple, la fonction supplante la dfinition de cd afin de crer un
raccourci simple. Nous souhaitons que la fonction interprte cd ... comme un dplacement vers deux niveaux suprieurs de rpertoire ; cest--dire cd ../.. (voir la recette
16.13, page 396). Les autres arguments conservent leur signification habituelle. Notre
fonction recherche simplement une correspondance avec ... et remplace cet argument
par sa signification relle. Mais, comment, depuis lintrieur de la fonction, pouvezvous invoquer la version relle de cd afin de changer de rpertoire ? La commande interne builtin demande bash de considrer que la commande en argument est celle dfinie en interne et non un alias ou une fonction. Nous nous en servons dans la fonction,
mais elle peut tre utilise tout moment pour faire rfrence, de manire non ambigu, une commande relle et passer outre toute fonction qui pourrait la supplanter.
Si le nom de votre fonction est celui dun programme excutable, comme ls, et non
dune commande interne, vous pouvez contourner les dfinitions dalias et/ou de fonctions en prcisant le chemin complet de lexcutable, par exemple /bin/ls la place de ls.
Si vous ne connaissez pas le nom de chemin complet, prfixez la commande par le motcl command et bash ignore toute dfinition dalias et de fonctions du nom de la commande et utilise la version relle. Cependant, sachez que la variable $PATH est toujours
consulte pour dterminer lemplacement de la commande. Si la mauvaise version de
ls est excute parce que votre $PATH contient des chemins inadquats, lajout de
command ne sera daucune aide.

Voir aussi

help builtin ;

help command ;

help type ;

la recette 14.4, Effacer tous les alias, page 296 ;

la recette 16.13, Concevoir une meilleure commande cd, page 396.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

11
Dates et heures

La manipulation des dates et les heures devrait tre simple, mais ce nest absolument pas
le cas. Que vous criviez un script shell ou un programme plus important, la gestion du
temps savre complexe : diffrents formats daffichage de lheure et de la date, prise en
charge des heures dt et dhiver, annes bissextiles, secondes intercalaires, etc. Par
exemple, imaginez que vous disposiez dune liste de contrats et des dates auxquelles ils
ont t signs. Vous aimeriez en calculer les dates dexpiration. Ce problme nest pas
aussi simple quil y parat. Une anne bissextile intervient-elle entre les deux dates ? Les
horaires dt et dhiver sont-ils importants dans ces contrats ? Quel format faut-il donner aux dates afin quelles ne soient pas ambigus ? 7/4/07 signifie-t-il 4 juillet 2007 ou
7 avril ?
Les dates et les heures se rencontrent dans tous les aspects de linformatique. Tt ou tard,
vous devrez les manipuler : dans les journaux du systme, dune application ou des transactions, dans les scripts de traitement des donnes, dans les tches utilisateur ou administratives, etc. Ce chapitre va vous aider les grer de manire aussi simple et nette que
possible. Les ordinateurs conservent les dates de manire trs prcise, notamment lorsquils utilisent le protocole NTP (Network Time Protocol) pour rester synchroniser avec
les valeurs nationales et internationales. Ils prennent galement bien en charge les passages aux horaires dt et dhiver en fonction des pays. Pour manipuler les dates dans
un script shell, vous avez besoin de la commande Unix date (ou, mieux encore, de la version GNU de la commande date, disponible en standard avec Linux). date est capable
dafficher des dates en diffrents formats et mme deffectuer correctement des calculs
sur les dates.
Notez que gawk (la version GNU de awk) emploie la mme mise en forme strftime que
la commande date de GNU. Nous nallons pas dtailler ici lutilisation de gawk, mais
nous verrons un exemple simple. Nous vous recommandons la variante GNU de date
car elle est plus facile employer et dispose de lindispensable option -d. Mais noubliez
pas gawk lorsque le systme dispose de cet outil mais pas de la version GNU de date.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

224

Chapitre 11 Dates et heures

11.1. Formater les dates en vue de leur


affichage
Problme
Vous souhaitez mettre en forme des dates ou des heures avant de les afficher.

Solution
Utilisez la commande date avec une spcification de format strftime. Pour la liste des spcifications de format reconnues, consultez la section Mettre en forme la date et lheure avec
strftime, page 544, ou la page de manuel de strftime.
# Dfinir des variables denvironnement est utile dans les scripts :
# Voir le site http://greenwichmeantime.com/info/iso.htm
$ STRICT_ISO_8601='%Y-%m-%dT%H:%M:%S%z'
# Presque ISO-8601, mais dans une forme plus lisible.
$ ISO_8601='%Y-%m-%d %H:%M:%S %Z'
$ ISO_8601_1='%Y-%m-%d %T %Z'

# %T quivaut %H:%M:%S

# Format adapt aux noms de fichiers.


$ DATE_FICHIER='%Y%m%d%H%M%S'
$ date "+$ISO_8601"
2006-05-08 14:36:51 CEST
gawk "BEGIN {print strftime(\"$ISO_8601\")}"
2006-12-07 04:38:54 CEST
# Identique $ISO_8601.
$ date '+%Y-%m-%d %H:%M:%S %Z'
2006-05-08 14:36:51 CEST
$ date -d '2005-11-06' "+$ISO_8601"
2005-11-06 00:00:00 CEST
$ date "+Programme dmarr : $ISO_8601"
Programme dmarr : 2006-05-08 14:36:51 CEST
$ printf "%b" "Programme dmarr : $(date '+$ISO_8601')\n"
Programme dmarr : $ISO_8601
$ echo "Je peux renommer le fichier ainsi : \
> mv fic.log fic_$(date +$DATE_FICHIER).log"
Je peux renommer le fichier ainsi : mv fic.log fic_20060508143724.log

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

11.2. Fournir une date par dfaut

225

Discussion
Vous pourriez tre tent de placer le caractre + dans la variable denvironnement afin
de simplifier ensuite la commande. Sur certains systmes, la commande date est assez
pointilleuse quant lexistence et au placement du +. Nous vous conseillons donc de
lajouter explicitement la commande date elle-mme.
Il existe dautres options de mise en forme. Pour en connatre la liste complte, consultez la page de manuel de date ou celle de la fonction C strftime() (man 3 strftime).
Sauf mention contraire, le fuseau horaire correspond celui dfini par votre systme.
Le format %z est une extension non standard disponible dans la version GNU de la commande date ; elle peut ne pas tre reconnue par votre systme.
Le format recommand pour laffichage des dates et des heures est le format ISO 8601.
Vous devez lutiliser autant que possible. Voici ses avantages par rapport aux autres formats daffichage :

il sagit dun standard reconnu ;

il est dpourvu de toute ambigut ;

il est facile lire tout en restant simple analyser par programme (par exemple
avec awk ou cut) ;

il est tri de manire adquate dans les donnes en colonne ou dans les noms de
fichiers.

Essayez dviter les formats MM/JJ/AA ou JJ/MM/AA, ou pire encore M/J/AA ou J/M/AA.
Leur tri nest pas adapt, ils sont ambigus, puisque le jour ou le mois peut arriver en premier en fonction du pays, et difficiles analyser. De mme, utilisez de prfrence un format horaire sur 24 heures afin dviter dautres problmes dambigut et danalyse.

Voir aussi

man date ;

http://www.cl.cam.ac.uk/~mgk25/iso-time.html ;

http://www.qsl.net/g1smd/isopdf.htm ;

http://greenwichmeantime.com/info/iso.htm ;

http://195.141.59.67/iso/fr/prods-services/popstds/datesandtime.html ;

la section Mettre en forme la date et lheure avec strftime, page 544.

11.2. Fournir une date par dfaut


Problme
Vous souhaitez que votre script fournisse une date par dfaut sense et invite lutilisateur la vrifier.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

226

Chapitre 11 Dates et heures

Solution
En utilisant la commande date de GNU, affectez la date probable une variable, puis
faites en sorte que lutilisateur puisse la corriger si ncessaire :
#!/usr/bin/env bash
# bash Le livre de recettes : date_par_defaut
# Utiliser midi afin d'viter que le script ne s'excute aux environs
# de minuit avec un dcalage de quelques secondes qui peuvent conduire
# des erreurs d'une journe.
DATE_DEBUT=$(date -d 'last week Monday 12:00:00' '+%Y-%m-%d')
while [ 1 ]; do
printf "%b" "La date de dbut est le $DATE_DEBUT, est-ce correct?
(O/autre date) "
read reponse
# Toute valeur autre que Entre, "O" ou "o" est comprise comme
# une nouvelle date. On pourrait utiliser "[Oo]*" pour accepter
# la saisie de "oui". La vrification de la nouvelle date se
# fait avec le format CCYY-MM-DD.
case "$reponse" in
[Oo]) break
;;
[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])
printf "%b" "$DATE_DEBUT est remplace par $reponse\n"
DATE_DEBUT="$reponse"
;;
*)

printf "%b" "Date invalide, veuillez recommencer...\n"


;;

esac
done
DATE_FIN=$(date -d "$DATE_DEBUT +7 days" '+%Y-%m-%d')
echo "DATE_DEBUT: $DATE_DEBUT"
echo "DATE_FIN:
$DATE_FIN"

Discussion
Si elle est reconnue par la version GNU de date, loption -d nest pas universellement
prise en charge. Nous vous conseillons dobtenir et dutiliser la version GNU, si possible.
Vous devez retirer le code de vrification si votre script sexcute sans surveillance ou
un moment dtermin (par exemple, partir de cron).
Pour plus dinformations sur la mise en forme des dates et des heures, consultez la recette 11.1, page 224.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

11.3. Calculer des plages de dates

227

Nous utilisons un code similaire celui-ci dans des scripts qui gnrent des requtes
SQL. Le script sexcute une heure donne et cre une requte SQL pour une plage de
dates prcise afin de gnrer un rapport.

Voir aussi

man date ;

la recette 11.1, Formater les dates en vue de leur affichage, page 224 ;

la recette 11.3, Calculer des plages de dates, page 227.

11.3. Calculer des plages de dates


Problme
Vous disposez dune premire date (peut-tre issue de la recette 11.2, page 225) et vous
souhaitez gnrer automatiquement la seconde.

Solution
La commande date de GNU est trs puissante et adaptable, mais les possibilits de son
option -d ne sont pas trs bien documentes. Sa documentation se trouve peut-tre
dans la page de manuel de getdate. Voici quelques exemples :
$ date '+%Y-%m-%d %H:%M:%S %z'
2005-11-05 01:03:00 -0500
$ date -d 'today' '+%Y-%m-%d %H:%M:%S %z'
2005-11-05 01:04:39 -0500
$ date -d 'yesterday' '+%Y-%m-%d %H:%M:%S %z'
2005-11-04 01:04:48 -0500
$ date -d 'tomorrow' '+%Y-%m-%d %H:%M:%S %z'
2005-11-06 01:04:55 -0500
$ date -d 'Monday' '+%Y-%m-%d %H:%M:%S %z'
2005-11-07 00:00:00 -0500
$ date -d 'this Monday' '+%Y-%m-%d %H:%M:%S %z'
2005-11-07 00:00:00 -0500
$ date -d 'last Monday' '+%Y-%m-%d %H:%M:%S %z'
2005-10-31 00:00:00 -0500
$ date -d 'next Monday' '+%Y-%m-%d %H:%M:%S %z'
2005-11-07 00:00:00 -0500

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

228

Chapitre 11 Dates et heures

$ date -d 'last week' '+%Y-%m-%d %H:%M:%S %z'


2005-10-29 01:05:24 -0400
$ date -d 'next week' '+%Y-%m-%d %H:%M:%S %z'
2005-11-12 01:05:29 -0500
$ date -d '2 weeks' '+%Y-%m-%d %H:%M:%S %z'
2005-11-19 01:05:42 -0500
$ date -d '-2 weeks' '+%Y-%m-%d %H:%M:%S %z'
2005-10-22 01:05:47 -0400
$ date -d '2 weeks ago' '+%Y-%m-%d %H:%M:%S %z'
2005-10-22 01:06:00 -0400
$ date -d '+4 days' '+%Y-%m-%d %H:%M:%S %z'
2005-11-09 01:06:23 -0500
$ date -d '-6 days' '+%Y-%m-%d %H:%M:%S %z'
2005-10-30 01:06:30 -0400
$ date -d '2000-01-01 +12 days' '+%Y-%m-%d %H:%M:%S %z'
2000-01-13 00:00:00 -0500
$ date -d '3 months 1 day' '+%Y-%m-%d %H:%M:%S %z'
2006-02-06 01:03:00 -0500

Discussion
Loption -d permet dindiquer une date prcise la place de maintenant, mais elle nest
pas reconnue par toutes les commandes date. La version GNU la prend en charge et
nous vous conseillons de linstaller et de lemployer autant que possible.
Lutilisation de loption -d peut tre complexe. Les arguments suivants fonctionnent
comme attendu :
$ date '+%a %Y-%m-%d'
sam 2005-11-05
$ date -d 'today' '+%a %Y-%m-%d'
sam 2005-11-05
$ date -d 'Saturday' '+%a %Y-%m-%d'
sam 2005-11-05
$ date -d 'last Saturday' '+%a %Y-%m-%d'
sam 2005-10-29
$ date -d 'this Saturday' '+%a %Y-%m-%d'
sam 2005-11-05

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

11.3. Calculer des plages de dates

229

En revanche, si vous excutez la commande suivante le samedi, vous nobtenez pas le


samedi suivant mais la date du jour mme :
$ date -d 'next Saturday' '+%a %Y-%m-%d'
sam 2005-11-05

Faites attention galement this week et aux JOURS, car sils font rfrence au pass, la
semaine en cours devient la semaine suivante. Si vous invoquez la commande ci-dessous
le samedi 5 novembre 2005, vous obtenez un rsultat sans doute diffrent de ce que vous
attendiez :
$ date -d 'this week Friday' '+%a %Y-%m-%d'
ven 2005-11-11

Loption -d peut savrer extrmement utile, mais vous devez tester votre code et inclure
le contrle derreur adquat.
Si vous ne disposez pas de la version GNU de date, vous serez sans doute intress par
les cinq fonctions dcrites dans larticle Shell Corner: Date-Related Shell Functions
du magazine UnixReview du mois de septembre 2005 :
pn_month
Le xme mois avant ou aprs le mois indiqu.
end_month
La fin du mois indiqu.
pn_day
Le xme jour avant ou aprs le jour indiqu.
cur_weekday
Le jour de la semaine correspondant au jour indiqu.
pn_weekday
Le xme de la semaine avant ou aprs le jour indiqu.
Les fonctions suivantes ont t ajoutes peu avant la publication de cet ouvrage :
pn_day_nr
(Non rcursive) Le xme jour avant ou aprs le jour indiqu.
days_between
Nombre de jours entre deux dates.
Notez que pn_month, end_month et cur_weekday sont indpendantes des autres fonctions. En revanche, pn_day sappuie sur pn_month et end_month, tandis que pn_weekday
repose sur pn_day et cur_weekday.

Voir aussi

man date ;

man getdate ;

http://www.unixreview.com/documents/s=9884/ur0509a/ur0509a.html ;

http://www.unixlabplus.com/unix-prog/date_function/ ;

la recette 11.2, Fournir une date par dfaut, page 225.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

230

Chapitre 11 Dates et heures

11.4. Convertir des dates et des heures en


secondes depuis lorigine
Problme
Vous souhaitez convertir une date et une heure en secondes depuis lorigine (epoch) afin
de faciliter les calculs arithmtiques sur les dates et les heures.

Solution
Utilisez la commande date de GNU avec loption -d et un format %s standard :
# Pour "maintenant", cest facile.
$ date '+%s'
1131172934
# Les autres dates ont besoin de loption non standard -d.
$ date -d '2005-11-05 12:00:00 +0000' '+%s'
1131192000

Discussion
Si vous ne disposez pas de la version GNU de la commande date, le problme est plus
difficile rsoudre. Nous vous conseillons donc dinstaller et dutiliser la version GNU
de date. Si cela ne vous est pas possible, vous serez peut-tre en mesure demployer Perl.
Voici trois manires dafficher linstant prsent en secondes depuis lorigine :
$ perl -e 'print time, qq(\n);'
1154158997
# Identique la prcdente.
$ perl -e 'use Time::Local; print timelocal(localtime( )) . qq(\n);'
1154158997
$ perl -e 'use POSIX qw(strftime); print strftime("%s", localtime( )) .
qq(\n);'
1154159097

La structure de donnes des dates et des heures en Perl complique la conversion dune
date autre que linstant prsent. Les annes dbutent en 1900 et les mois (mais pas les
jours) commencent zro et non un. Le format de la commande est timelocal(sec,
min, heure, jour, mois-1, anne-1900). Par consquent, voici comment convertir linstant 2005-11-05 06:59:49 en secondes depuis lorigine :
# Lheure indique est une heure locale.
$ perl -e 'use Time::Local; print timelocal("49", "59", "06", "05", "10",
"105") . qq(\n);'
1131191989

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

11.5. Convertir des secondes depuis lorigine en dates et heures

231

# Lheure indique est une heure UTC.


$ perl -e 'use Time::Local; print timegm("49", "59", "06", "05", "10",
"105") . qq(\n);'
1131173989

Voir aussi

man date ;

la recette 11.5, Convertir des secondes depuis lorigine en dates et heures, page 231 ;

la section Mettre en forme la date et lheure avec strftime, page 544.

11.5. Convertir des secondes depuis lorigine en


dates et heures
Problme
Vous souhaitez convertir des secondes depuis lorigine en une date et une heure lisibles.

Solution
Utilisez la commande date de GNU avec lun des formats de la recette 11.1, page 224 :
ORIGINE='1131173989'
$ date -d "1970-01-01 UTC $ORIGINE seconds" +"%Y-%m-%d %T %z"
2005-11-05 01:59:49 -0500
$ date --utc --date "1970-01-01 $ORIGINE seconds" +"%Y-%m-%d %T %z"
2005-11-05 06:59:49 +0000

Discussion
Puisque les secondes correspondent simplement une valeur depuis lorigine (fixe au
1er janvier 1970 minuit, ou 1970-01-01T00:00:00), cette commande dbute lorigine,
ajoute les secondes de lorigine et affiche la date et lheure au format indiqu.
Sans la version GNU de date, vous pouvez essayer les lignes de commandes Perl suivantes :
ORIGINE='1131173989'
$ perl -e "print scalar(gmtime($ORIGINE)), qq(\n);"
Sat Nov 5 06:59:49 2005

# UTC

$ perl -e "print scalar(localtime($ORIGINE)), qq(\n);"


Sat Nov 5 01:59:49 2005

# Lheure locale.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

232

Chapitre 11 Dates et heures

$ perl -e "use POSIX qw(strftime); print strftime('%Y-%m-%d %H:%M:%S',


localtime($ORIGINE)), qq(\n);"
2005-11-05 01:59:49

Voir aussi

man date ;

la recette 11.1, Formater les dates en vue de leur affichage, page 224 ;

la recette 11.4, Convertir des dates et des heures en secondes depuis lorigine, page 230 ;

la section Mettre en forme la date et lheure avec strftime, page 544.

11.6. Dterminer hier ou demain en Perl


Problme
Vous avez besoin de la date dhier ou de demain. La version GNU de date nest pas installe sur votre systme, mais vous disposez de Perl.

Solution
Utilisez la commande Perl suivante, en ajustant le nombre de secondes ajoutes ou
soustraites de time :
# Hier, la mme heure (noter la soustraction).
$ perl -e "use POSIX qw(strftime); print strftime('%Y-%m-%d', localtime(time
- 86400)), qq(\n);"
# Demain, la mme heure (noter laddition).
$ perl -e "use POSIX qw(strftime); print strftime('%Y-%m-%d', localtime(time
+ 86400)), qq(\n);"

Discussion
Il sagit simplement dune version particulire des recettes prcdentes, mais elle est tellement classique quelle mritait dtre mentionne sparment. La recette 11.7, page
233, contient un tableau de valeurs qui pourra vous tre utile.

Voir aussi

la recette 11.2, Fournir une date par dfaut, page 225 ;

la recette 11.3, Calculer des plages de dates, page 227 ;

la recette 11.4, Convertir des dates et des heures en secondes depuis lorigine, page 230 ;

la recette 11.5, Convertir des secondes depuis lorigine en dates et heures, page 231 ;

la recette 11.7, Calculer avec des dates et des heures, page 233 ;

la section Mettre en forme la date et lheure avec strftime, page 544.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

11.7. Calculer avec des dates et des heures

233

11.7. Calculer avec des dates et des heures


Problme
Vous souhaitez effectuer des calculs arithmtiques sur des dates et des heures.

Solution
Si vous ne pouvez obtenir la rponse adquate laide de la commande date (voir la recette 11.3, page 227), convertissez les dates et les heures existantes en secondes depuis
lorigine (voir la recette 11.4, page 230), effectuez vos calculs, puis convertissez les secondes rsultantes au format souhait (voir la recette 11.5, page 231).
Si la version GNU de date nexiste pas sur votre systme, vous pouvez
vous tourner vers les fonctions du shell dcrites dans larticle Shell
Corner: Date-Related Shell Functions de Unix Review de septembre
2005 (voir la recette 11.3, page 227).

Par exemple, supposons que vous ayez des donnes de journalisation provenant dune
machine dont lhorloge est dcale. Aujourdhui, le protocole NTP (Network Time Protocol) est largement utilis et cette situation ne devrait donc pas se produire, mais faisons
malgr tout cette hypothse :
CORRECTION='172800'

# 2 jours en secondes.

# Placer ici le code qui extrait la partie date des donnes dans
# la variable $date_erronee.
# Supposer que la date est la suivante :
date_erronee='Jan 2 05:13:05' # Date au format syslog.
# Convertir la date en secondes depuis lorigine avec date de GNU :
origine_erronee=$(date -d "$date_erronee" '+%s')
# Appliquer la correction.
origine_correcte=$(( origine_erronee + $CORRECTION ))
# Convertir la date corrige en un format lisible.
date_correcte=$(date -d
"1970-01-01 UTC $origine_correcte seconds") # GNU Date.
date_correcte_iso=$(date -d
"1970-01-01 UTC $origine_correcte seconds" +'%Y-%m-%d %T')
echo
echo
echo
echo
echo

[05/03/08]

bash Le livre de recettes

"Date errone :
"Origine errone :
"Correction :
"Origine valide :
"Date valide :

# GNU Date.

$date_erronee"
$origine_erronee"
+$CORRECTION"
$origine_correcte"
$date_correcte"

Elodie FRITSCH <elodie.fritsch@total.com>

234

Chapitre 11 Dates et heures

echo "Date valide ISO :

$date_correcte_iso"

# Placer ici le code pour rinsrer $date_correcte dans les donnes.


Attention aux annes ! Certaines commandes Unix, comme ls et syslog
tentent de produire une sortie plus facile lire et omettent, dans certains cas, lanne. Vous devrez prendre en compte cet aspect lors du calcul du facteur de correction. Si les dates sont dans un intervalle important ou correspondent des fuseaux horaires diffrents, vous devrez
placer les donnes dans des fichiers spars et les traiter individuellement.

Discussion
Pour effectuer des calculs arithmtiques sur des dates, il est beaucoup plus facile demployer les secondes coules depuis lorigine que nimporte quel autre format. En effet,
vous navez alors pas vous occuper des heures, des jours, des semaines ou des annes,
mais simplement additionner ou soustraire des valeurs. Cette approche vite galement des oprations complexes dues aux annes bissextiles, aux secondes intercalaires
et aux fuseaux horaires.
Le tableau 11-1 liste quelques valeurs qui pourraient vous servir.
Tableau 11-1. Table de conversion des principales valeurs depuis lorigine
Secondes

Minutes

Heures

Jours

60

300

600

10

3 600

60

18 000

300

36 000

600

10

86 400

1 440

24

172 800

2 880

48

604 800

10 080

168

1 209 600

20 160

336

14

2 592 000

43 200

720

30

31 536 000

525 600

8 760

365

Voir aussi

http://www.jpsdomain.org/networking/time.html ;

la recette 11.3, Calculer des plages de dates, page 227 ;

la recette 11.4, Convertir des dates et des heures en secondes depuis lorigine, page 230 ;

la recette 11.5, Convertir des secondes depuis lorigine en dates et heures, page 231 ;

la recette 13.12, Extraire certains champs des donnes, page 273.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

11.8. Grer les fuseaux horaires, les horaires dt et les annes bissextiles

235

11.8. Grer les fuseaux horaires, les horaires


dt et les annes bissextiles
Problme
Vous devez tenir compte des fuseaux horaires, des horaires dt et dhiver, ainsi que des
annes bissextiles ou des secondes intercalaires.

Solution
Nous vous le dconseillons fortement. Ces paramtres demandent une gestion beaucoup plus complexe quil ny parat. Laissez-la au code existant et test depuis des annes. Optez pour un outil qui est en mesure de rpondre vos besoins. Il est fort probable
que lune des recettes de ce chapitre ait dj prsent une solution adquate, probablement base sur la version GNU de date. Dans le cas contraire, il existe trs certainement
un outil qui fera laffaire. Par exemple, de nombreux modules Perl permettent de manipuler des dates et des heures.
Nous ne plaisantons pas. Il est extrmement compliqu de prendre en compte ces particularits des dates. vitez-vous dintenses maux de tte en utilisant simplement un
outil adapt.

Voir aussi

la recette 11.1, Formater les dates en vue de leur affichage, page 224 ;

la recette 11.3, Calculer des plages de dates, page 227 ;

la recette 11.4, Convertir des dates et des heures en secondes depuis lorigine, page 230 ;

la recette 11.5, Convertir des secondes depuis lorigine en dates et heures, page 231 ;

la recette 11.7, Calculer avec des dates et des heures, page 233.

11.9. Utiliser date et cron pour excuter un


script au nme jour
Problme
Vous devez excuter un script un certain jour de chaque mois (par exemple, le deuxime
mercredi), mais les outils cron ne vous offrent pas cette possibilit.

Solution
Ajoutez un peu de code shell la commande excute. Dans la crontab de Vixie Cron
pour Linux, adaptez lune des lignes suivantes. Si vous vous servez dun autre programme cron, vous devrez sans doute convertir les noms des jours de la semaine en nombres

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

236

Chapitre 11 Dates et heures

conformes au modle de votre version de cron (06 ou 17) et utiliser +%w (jour de la
semaine en version numrique) la place de +%a (nom de la semaine abrg dpendant
des paramtres rgionaux) :
# Vixie Cron
# Min Heure JduM Mois JdelaS Programme
# 0-59 0-23 1-31 1-12 0-7
# excuter le premier mercredi 23:00.
00 23 1-7 * Wed [ "$(date '+%a')" == "mer" ] && /chemin/de/la/commande
arguments de la commande
# excuter le deuxime jeudi 23:00.
00 23 8-14 * Thu [ "$(date '+%a')" == "jeu" ] && /chemin/de/la/commande
# excuter le troisime vendredi 23:00.
00 23 15-21 * Fri [ "$(date '+%a')" == "ven" ] && /chemin/de/la/commande
# excuter le quatrime samedi 23:00.
00 23 22-27 * Sat [ "$(date '+%a')" == "sam" ] && /chemin/de/la/commande
# excuter le cinquime dimanche 23:00.
00 23 28-31 * Sun [ "$(date '+%a')" == "dim" ] && /chemin/de/la/commande
Notez quun jour de la semaine nest pas systmatiquement prsent
cinq fois dans un mois. Vous devez donc bien rflchir ce que vous
souhaitez faire avant de planifier une tche pour la cinquime semaine
du mois.

Discussion
La plupart des versions de cron (y compris Vixie Cron pour Linux) ne permettent pas de
planifier une tche pour le Nme jour du mois. Pour contourner ce problme, nous prvoyons lexcution de la tche lintrieur de la plage de jours qui inclut le Nme jour.
Ensuite, nous vrifions si le jour courant correspond celui du lancement de la tche.
Le deuxime mercredi du mois se trouve entre le 8e et le 14e jour du mois. Nous
planifions donc lexcution de la tche tous les jours de cet intervalle, mais vrifions que
le jour courant est bien un mercredi. Dans ce cas, la commande est excute.
Le tableau 11-2 prsente les intervalles employs prcdemment.
Tableau 11-2. Intervalles des semaines dun mois
Semaine
Premire

17

Deuxime

8 14

Troisime

15 21

Quatrime

22 27

Cinquime (voir lavertissement)

28 31

[05/03/08]

bash Le livre de recettes

Plages de jours

Elodie FRITSCH <elodie.fritsch@total.com>

11.9. Utiliser date et cron pour excuter un script au nme jour

237

Si cela vous parat trop simple, consultez un calendrier pour vous convaincre :
$ cal 10 2006
octobre 2006
lu ma me je ve sa di
2
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 29

Voir aussi

man 5 crontab ;

man cal.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

12
Tches utilisateur sous
forme de scripts shell
Jusqu prsent, vous avez t confront un grand nombre de petits scripts et de formes
syntaxiques. Par ncessit, les exemples avaient une porte et une taille limites. Nous
voudrions maintenant vous prsenter des exemples plus vastes, mais qui ne sont pas
pour autant plus longs. Il sagit dexemples de scripts shell rels qui ne se limitent pas
aux tches dadministration systme. Vous les trouverez probablement utiles et pratiques. Par ailleurs, leur tude vous permettra den apprendre plus sur bash et vous les
adapterez peut-tre vos propres besoins.

12.1. Afficher une ligne de tirets


Problme
Afficher une ligne de tirets avec une commande simple peut sembler facile (cest le cas).
Mais, ds quun script simple est crit, il a tendance vouloir grandir. Vous voulez varier
la longueur de la ligne de tirets. Vous voulez que le tiret puisse tre remplac par un
caractre indiqu par lutilisateur. Ltendue des fonctionnalits peut ainsi augmenter
trs facilement. Pouvez-vous crire un script simple qui tient compte de toutes ces extensions sans devenir trop complexe ?

Solution
Envisagez le script suivant :
1
2
3
4
5
6
7
8
9

#!/usr/bin/env bash
# bash Le livre de recettes : tirets
# tirets - affiche une ligne de tirets
# options : # longueur de la ligne (72 par dfaut)
#
-c X utiliser le caractre X la place du tiret
#
function utiliserquitter ()
{
printf "usage : %s [-c X] [#]\n" $(basename $0)

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

240

Chapitre 12 Tches utilisateur sous forme de scripts shell

10
11

exit 2
} >&2

12
13
14
15
16
17
18
19
20
21
22
23

LONGUEUR=72
CARACTERE='-'
while (( $# > 0 ))
do
case $1 in
[0-9]*) LONGUEUR=$1;;
-c) shift
CARACTERE=$1;;
*) utiliserquitter;;
esac
shift
done

24
25
26
27
28

if (( LONGUEUR > 4096 ))


then
echo "trop long" >&2
exit 3
fi

29
30
31
32
33
34
35

# Construire la chane la longueur exacte.


TIRETS=""
for ((i=0; i<LONGUEUR; i++))
do
TIRETS="${TIRETS}${CARACTERE}"
done
printf "%s\n" "$TIRETS"

Discussion
Le cur du script consiste construire une chane compose du nombre demand de
tirets (ou du caractre indiqu) et lafficher sur la sortie standard (STDOUT). Cela ne
demande que six lignes de code (3035). Les lignes 12 et 13 fixent des valeurs par dfaut.
Toutes les autres lignes concernent lanalyse des arguments, le contrle des erreurs, les
messages dutilisation et les commentaires.
Tous ces aspects sont indispensables dans les scripts destins lutilisateur final. Moins
de 20 % du code ralise plus de 80 % du travail. Cependant, ce sont ces 80 % du code qui
font que le script est robuste et facile dutilisation.
la ligne 9, nous utilisons basename pour retirer le chemin lors de laffichage du nom
du script. Ainsi, quelle que soit la manire dont lutilisateur a invoqu le script (par
exemple, ./tirets, /home/nom_utilisateur/bin/tirets ou mme ../../par/ici/tirets), le message
dutilisation affiche uniquement tirets.
Lanalyse des arguments se fait tant quil en reste sur la ligne de commande (ligne 14).
Lorsquun argument a t trait, une instruction shift dcrmente le nombre darguments restants et la boucle while finit par se terminer. Seuls deux arguments sont
accepts : un nombre prcisant la longueur de la chane (ligne 17) et une option -c sui-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

12.2. Prsenter des photos dans un album

241

vie dun caractre (lignes 1819). Tout autre argument (ligne 20) conduit laffichage
du message dutilisation et la terminaison du script.
Nous pourrions tre plus prcis dans le traitement de -c et de son argument. Sans une
analyse plus sophistique (par exemple base sur getopt ; voir la recette 13.1, page 257),
loption et son argument doivent tre spars par une espace. Pour lexcution du script,
vous devez crire -c n et non -cn. Par ailleurs, nous ne vrifions pas que le deuxime
argument est bien prsent, ni son contenu ; il peut trs bien tre une chane ou une seule lettre. (Pouvez-vous imaginer une manire simple de traiter ce cas, en prenant uniquement le premier caractre de largument ? Avez-vous besoin de le prendre en
compte ? Pourquoi ne pas laisser lutilisateur indiquer une chane la place dun
caractre ?)
Lanalyse de largument numrique pourrait galement sappuyer sur des techniques
plus labores. Les motifs dune instruction case se conforment aux rgles de lexpansion des noms de chemin et ne sont en aucun cas des expressions rgulires. Vous pourriez croire que le motif [0-9]* de case reprsente uniquement des chiffres, mais cette
signification est celle des expressions rgulires. Dans une instruction case, il indique
simplement une chane qui commence par un chiffre. En ninterceptant pas les entres
invalides, comme 9.5 ou 612etplus, les erreurs surgissent plus loin dans le script. Une
instruction if avec une expression rgulire plus sophistique serait bien utile ici.
Enfin, vous aurez remarqu que le script fixe, en ligne 24, une taille maximum, mme
si elle est totalement arbitraire. Devez-vous conserver ou supprimer cette contrainte ?
partir de cet exemple, vous pouvez constater que mme les scripts simples peuvent
devenir plus complexes, principalement cause de la gestion des erreurs, de lanalyse
des arguments et des autres oprations connexes. Pour les scripts utiliss uniquement
par leur auteur, la gestion de ces aspects peut tre rduite ou mme omise. En effet, en
tant que seul utilisateur de script, son crateur en connat le bon usage et accepte tout
message derreur en cas de dysfonctionnement. En revanche, si les scripts doivent tre
partags avec dautres utilisateurs, il est important de faire des efforts pour les rendre
plus robustes et faciles dutilisation.

Voir aussi

la recette 5.8, Parcourir les arguments dun script, page 96 ;

la recette 5.11, Compter les arguments, page 101 ;

la recette 5.12, Extraire certains arguments, page 103 ;

la recette 6.15, Analyser les arguments de la ligne de commande, page 139 ;

la recette 13.1, Analyser les arguments dun script, page 257.

12.2. Prsenter des photos dans un album


Problme
Vous avez enregistr toutes les photos de votre appareil numrique dans un rpertoire
et vous souhaitez disposer dun moyen rapide et facile de les visualiser toutes afin de ne
conserver que les plus russies.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

242

Chapitre 12 Tches utilisateur sous forme de scripts shell

Solution
crivez un script shell qui gnre un ensemble de pages HTML permettant de visualiser
vos photos dans un navigateur. Nommez ce script creer_album et placez-le dans un rpertoire comme ~/bin.
Depuis la ligne de commande, utilisez cd pour aller dans le rpertoire o lalbum doit
tre cr (par exemple celui des photos). Ensuite, excutez les commandes qui vont gnrer la liste des photos inclure dans cet album (par exemple, ls *.jpg, mais consultez
galement la recette 9.5, page 195) et dirigez leur sortie vers le script creer_album (voir
ci-aprs). Vous devez indiquer le nom de lalbum (cest--dire le nom dun rpertoire qui
sera cr par le script) sur la ligne de commande en seul argument au script shell. Voici
un exemple dinvocation :
$ ls *.jpg | creer_album matchRugby

La figure 12-1 prsente un exemple de la page web gnre.

Figure 12-1. Exemple de page web produite par creer_album


Le titre correspond la photo (le nom de son fichier). Des liens hypertextes permettent
daller aux autres pages (premire, prcdente, suivante et dernire).
Voici le script shell (creer_album) qui gnre les pages HTML, une pour chaque image
(les numros de ligne ne font pas partie du script, mais simplifient les explications) :
1
2
3
4
5

#!/usr/bin/env bash
# bash Le livre de recettes : creer_album
# creer_album - cre un "album" HTML partir des fichiers de photos.
# ver. 0.2
#

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

12.2. Prsenter des photos dans un album

243

6
# Un album est un rpertoire de pages HTML. Il est cr dans le
7
# rpertoire de travail.
8
#
9
# Une page de l'album contient le code HTML permettant d'afficher
10
# une photo, avec un titre (le nom du fichier de la photo) et des
11
# liens hypertextes pour la premire photo, la prcdente, la suivante
12
# et la dernire.
13
#
14
# AFFICHER_ERREUR
15
AFFICHER_ERREUR()
16
{
17
printf "%b" "$@"
18
} >&2
19
20
#
21
# USAGE
22
USAGE()
23
{
24
AFFICHER_ERREUR "usage : %s <nouv_rp>\n" $(basename $0)
25
}
26
27
# GENERER(cetteph, premph, precph, suivph, dernph)
28
GENERER()
29
{
30
CETTEPH="../$1"
31
PREMPH="${2%.*}.html"
32
PRECPH="${3%.*}.html"
33
SUIVPH="${4%.*}.html"
34
DERNPH="${5%.*}.html"
35
if [ -z "$3" ]
36
then
37
LIGNEPREC='<TD> Pr&eacute;c&eacute;dente </TD>'
38
else
39
LIGNEPREC='<TD> <A HREF="'$PRECPH'"> Pr&eacute;c&eacute;dente </A>
</TD>'
40
fi
41
if [ -z "$4" ]
42
then
43
LIGNESUIV='<TD> Suivante </TD>'
44
else
45
LIGNESUIV='<TD> <A HREF="'$SUIVPH'"> Suivante </A> </TD>'
46
fi
47
cat <<EOF
48
<HTML>
49
<HEAD><TITLE>$CETTEPH</TITLE></HEAD>
50
<BODY>
51
<H2>$CETTEPH</H2>
52
<TABLE WIDTH="25%">
53
<TR>
54
<TD> <A HREF="$PREMPH"> Premi&egrave;re </A> </TD>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

244

Chapitre 12 Tches utilisateur sous forme de scripts shell

55
$LIGNEPREC
56
$LIGNESUIV
57
<TD> <A HREF="$DERNPH"> Derni&egrave;re </A> </TD>
58
</TR>
59
</TABLE>
60
<IMG SRC="$CETTEPH" alt="$CETTEPH"
61
BORDER="1" VSPACE="4" HSPACE="4"
62
WIDTH="800" HEIGHT="600"/>
63
</BODY>
64
</HTML>
65
EOF
66
}
67
68
if (( $# != 1 ))
69
then
70
USAGE
71
exit -1
72
fi
73
ALBUM="$1"
74
if [ -d "${ALBUM}" ]
75
then
76
AFFICHER_ERREUR "Le rpertoire [%s] existe dj.\n" ${ALBUM}
77
USAGE
78
exit -2
79
else
80
mkdir "$ALBUM"
81
fi
82
cd "$ALBUM"
83
84
PREC=""
85
PREM=""
86
DERN="derniere"
87
88
while read PHOTO
89
do
90
# Le dpart.
91
if [ -z "${ENCOURS}" ]
92
then
93
ENCOURS="$PHOTO"
94
PREM="$PHOTO"
95
continue
96
fi
97
98
FICHIERPH=$(basename "${ENCOURS}")
99
GENERER "$ENCOURS" "$PREM" "$PREC" "$PHOTO" "$DERN" >
"${FICHIERPH%.*}.html"
100
101
# Prparer l'itration suivante.
102
PREC="$ENCOURS"
103
ENCOURS="$PHOTO"

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

12.2. Prsenter des photos dans un album

245

104
105
done
106
107
FICHIERPH=$(basename ${ENCOURS})
108
GENERER "$ENCOURS" "$PREM" "$PREC"
"" "$DERN" >
"${FICHIERPH%.*}.html"
109
110
# Crer le lien pour "dernire"
111
ln -s "${FICHIERPH%.*}.html" ./derniere.html
112
113
# Crer un lien pour index.html.
114
ln -s "${PREM%.*}.html" ./index.html

Discussion
Mme sil existe de nombreux outils gratuits ou bon march pour la visualisation des
photos, lutilisation de bash pour construire un album photo simple permet dillustrer
la puissance de la programmation shell et constitue un bon exemple de travail.
Le script commence (ligne 1) par le commentaire spcial qui prcise lexcutable servant
lancer ce script. Ensuite, quelques commentaires dcrivent lobjectif du script. Mme
les commentaires les plus courts ont une importance lorsque vous devez, trois jours ou
13 mois plus tard, vous rappeler le fonctionnement du script.
Aprs les commentaires, nous avons plac les dfinitions des fonctions. La fonction
AFFICHER_ERREUR (lignes 1518) se comporte de manire trs similaire printf (puisquelle invoque simplement printf) mais en redirigeant sa sortie sur lerreur standard.
Ainsi, vous ntes pas oblig de rediriger la sortie pour chaque message derreur.
En gnral, la redirection est place la fin de la commande. Dans notre cas, nous lajoutons la fin de la dfinition de la fonction (ligne 18) pour indiquer bash de rediriger
toutes les sorties manant de cette fonction.
Mme sil nest pas absolument ncessaire de la placer dans une fonction spare, la
fonction USAGE (lignes 2225) est une bonne manire de documenter lutilisation de votre script. Au lieu de figer le nom du script dans le message dutilisation, nous prfrons
employer la variable spciale $0, par exemple pour le cas o le script changerait de nom.
Puisque $0 contient le nom du script au moment de son invocation, elle peut galement inclure le nom de chemin complet utilis pour invoquer le script (par exemple,
/usr/local/bin/creer_album). Ce chemin se retrouve alors dans le message dutilisation.
Grce la commande basename (ligne 24), nous retirons cette partie.
La fonction GENERER (lignes 2866) est plus longue. Son rle est de gnrer le code
HTML pour chaque page de lalbum, qui se trouve dans sa propre page web (statique),
avec des liens hypertextes vers la premire image, limage prcdente, limage suivante
et la dernire image. La fonction GENERER nest pas complexe. Elle reoit les noms de toutes les images relier. Elle prend ces noms et les convertit en noms de pages, ce qui, dans
notre script, consiste remplacer lextension du fichier de limage par html. Par exemple, si $2 contient le nom de fichier pict001.jpg, le rsultat de ${2%.*}.html est
pict001.html.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

246

Chapitre 12 Tches utilisateur sous forme de scripts shell

Puisque le code HTML produire est court, nous nutilisons pas une suite dinstructions printf, mais une commande cat avec un here document (ligne 47). Nous pouvons
ainsi saisir littralement le code HTML dans le script, ligne aprs ligne, tout en gardant
lexpansion des variables du shell. La commande cat recopie simplement (concatne)
STDIN sur STDOUT. Dans notre script, nous redirigeons STDIN de manire ce que les
lignes de texte qui suivent, cest--dire le here document, constituent lentre. En ne plaant pas le mot de fin dentre entre apostrophes (simplement EOF et non 'EOF' ou
\EOF), bash effectue la substitution des variables sur les lignes dentre. Nous pouvons
donc utiliser des noms de variables bass sur nos paramtres pour les diffrents titres et
liens hypertextes.
Nous aurions pu passer un nom de fichier la fonction GENERER et lui demander de rediriger sa propre sortie vers ce fichier. Mais une telle redirection nest pas vraiment logique dans une fonction de gnration (contrairement AFFICHER_ERREUR dont le seul
objectif est la redirection). Le rle de GENERER est de crer le contenu HTML. La destination de ce contenu ne la concerne pas. Puisque bash nous permet de rediriger trs facilement la sortie, il est possible de procder en plusieurs tapes. Par ailleurs, le
dbogage est plus facile lorsque la mthode affiche sa sortie sur STDOUT.
Les deux dernires commandes du script (lignes 111 et 114) crent des liens symboliques
servant de raccourcis vers la premire et la dernire photo. Ainsi, le script na pas besoin
de dterminer le nom de la premire et de la dernire page de lalbum. Il utilise simplement des noms figs, index.html et derniere.html, lors de la gnration des autres pages
de lalbum. Puisque le dernier fichier trait correspond la dernire photo de lalbum,
il suffit de crer un lien vers ce fichier. La premire photo est traite de manire similaire. Mme si nous connaissons son nom ds le dbut, nous attendons la fin du script
pour regrouper la cration des deux liens symboliques. Ce nest quune question de style, pour que les oprations de mme type restent ensemble.

Voir aussi

http://www.w3schools.com/ ;

HTML & XHTML La rfrence, 6e dition de Chuch Musciano et Bill Kennedy (dition OReilly) ;

la recette 3.2, Conserver les donnes avec le script, page 60 ;

la recette 3.3, Empcher un comportement trange dans un here document, page 61 ;

la recette 3.4, Indenter un here document, page 63 ;

la recette 5.13, Obtenir des valeurs par dfaut, page 104 ;

la recette 5.14, Fixer des valeurs par dfaut, page 105 ;

la recette 5.18, Modifier certaines parties dune chane, page 109 ;

la recette 5.19, Utiliser les tableaux, page 111 ;

la recette 9.5, Retrouver des fichiers sans tenir compte de la casse, page 195 ;

la recette 16.9, Crer son rpertoire priv dutilitaires, page 389.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

12.3. Charger votre lecteur MP3

247

12.3. Charger votre lecteur MP3


Problme
Vous disposez dun ensemble de fichiers MP3 que vous aimeriez placer sur votre lecteur
MP3. Cependant, le nombre des fichiers dpasse la capacit de votre lecteur. Comment
pouvez-vous recopier vos fichiers audio sans avoir surveiller chaque copie pour dterminer si le lecteur est plein ou non ?

Solution
Utilisez un script shell qui vrifiera la capacit disponible lors de la copie des fichiers sur
le lecteur MP3 et qui sarrte lorsquil est plein.
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
29
30
31
32
33
34

#!/usr/bin/env bash
# bash Le livre de recettes : charger_mp3
# Remplit un lecteur MP3 avec le maximum de titres possible.
# N.B.: on suppose que le lecteur MP3 est mont sur /media/mp3.
#
#
# Dterminer la taille d'un fichier.
#
function TAILLE_FICHIER ()
{
NF=${1:-/dev/null}
if [[ -e $NF ]]
then
# FZ=$(ls -s $NF | cut -d ' ' -f 1)
set -- $(ls -s "$NF")
FZ=$1
fi
}
#
# Calculer l'espace disponible sur le lecteur MP3.
#
function ESPACE_LIBRE
{
# LIBRE=$(df /media/mp3 | awk '/^\/dev/ {print $4}')
set -- $(df /media/mp3 | grep '^/dev/')
LIBRE=$4
}
# Soustraire la TAILLE_FICHIER (donne) de l'espace disponible (global).
function DIMINUER ()
(( LIBRE-=${1:-0}))

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

248
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

Chapitre 12 Tches utilisateur sous forme de scripts shell


#
# Code principal :
#
let SOMME=0
let COMPTE=0
export FZ
export LIBRE
ESPACE_LIBRE
find . -name '*.mp3' -print | \
(while read NOM_CHEMIN
do
TAILLE_FICHIER "$NOM_CHEMIN"
if ((FZ <= LIBRE))
then
echo charger $NOM_CHEMIN
cp "$NOM_CHEMIN" /media/mp3
if (( $? == 0 ))
then
let SOMME+=FZ
let COMPTE++
DIMINUER $FZ
else
echo "erreur de copie de $NOM_CHEMIN sur /media/mp3"
rm -f /media/mp3/$(basename "$NOM_CHEMIN")
# Recalculer car on ne sait pas combien a t copi.
ESPACE_LIBRE
fi
# Une raison de poursuivre ?
if (( LIBRE <= 0 ))
then
break
fi
else
echo sauter $NOM_CHEMIN
fi
done
printf "%d chansons (%d blocs) ont t charges" $COMPTE $SOMME
printf " sur /media/mp3 (%d blocs libres)\n" $LIBRE
)
# Fin du script.

Discussion
Invoquez ce script et il copie tous les fichiers MP3 qui se trouvent dans le rpertoire de
travail et ses sous-rpertoires vers un lecteur MP3 (ou un autre priphrique) mont sur
/media/mp3. Le script tente de dterminer lespace disponible sur le priphrique avant
deffectuer la copie, puis il soustrait la taille des lments copis de celle du disque afin
de savoir quand sarrter (cest--dire lorsque le priphrique est plein ou aussi plein que
possible).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

12.3. Charger votre lecteur MP3

249

Linvocation du script est simple :


$ charger_mp3

Vous pouvez vous asseoir et le regarder copier les fichiers ou bien aller prendre un caf
(selon la rapidit des critures dans la mmoire de votre lecteur MP3).
Examinons quelques fonctionnalits de bash employes par ce script.
Commenons la ligne 35, aprs les commentaires et les dfinitions de fonctions. Nous
reviendrons par la suite aux fonctions. Le corps principal du script shell commence par
initialiser des variables (lignes 3839) et en exporte certaines afin quelles soient disponible globalement. la ligne 42, nous invoquons la fonction ESPACE_LIBRE pour dterminer lespace disponible sur le lecteur MP3 avant de dbuter la copie des fichiers.
La ligne 43 montre la commande find qui retrouve tous les fichiers MP3 (en ralit, uniquement ceux dont les noms se terminent par .mp3 ). Cette information est envoye
une boucle while, qui dbute la ligne 44.
Pourquoi la boucle while est-elle place entre des parenthses ? Les instructions lintrieur des parenthses seront excutes dans un sous-shell. Mais, ce qui nous intresse
ici, cest de regrouper linstruction while avec les instructions printf suivantes (lignes 71
et 72). Puisque chaque instruction dun tube est excute dans son propre sous-shell et
puisque la commande find envoie sa sortie vers la boucle while, aucun comptage effectu lintrieur de la boucle while nest donc disponible en dehors de cette boucle. En
plaant des instructions while et printf dans un sous-shell, elles sont excutes dans le
mme environnement et peuvent partager des variables.
tudions le contenu de la boucle while :
46
47
48
49
50
51
52

TAILLE_FICHIER "$NOM_CHEMIN"
if ((FZ <= LIBRE))
then
echo charger $NOM_CHEMIN
cp "$NOM_CHEMIN" /media/mp3
if (( $? == 0 ))
then

Pour chaque nom de fichier lu (depuis la sortie de la commande find), elle invoque la
fonction TAILLE_FICHIER pour dterminer la taille de ce fichier (voir ci-aprs pour lexplication de cette fonction). Ensuite, elle vrifie (ligne 47) si le fichier est plus petit que
lespace disque restant, autrement dit sil peut tre copi. Si cest le cas, elle affiche le
nom du fichier puis le copie (ligne 50) sur le lecteur MP3.
Il est important de vrifier que la copie sest bien passe (ligne 51). La variable $? contient le rsultat de la commande prcdente, cest--dire de cp. Si la copie a russi, nous
dduisons alors sa taille de lespace disponible sur le lecteur MP3. En revanche, si elle a
chou, nous devons essayer de supprimer la copie (car, si elle se trouve sur le lecteur,
elle est incomplte). Loption -f de rm nous permet dviter les messages derreur si le
fichier na pas t cr. Nous recalculons ensuite lespace disponible afin que les comptes soient bons. En effet, la copie peut avoir chou cause dune mauvaise estimation
(lespace disponible ntait pas suffisant).
Dans la partie principale du script, les trois instructions if (lignes 47, 51 et 63) utilisent
les doubles parenthses autour de lexpression. Ces trois instructions if sont numri-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

250

Chapitre 12 Tches utilisateur sous forme de scripts shell

ques et nous voulions utiliser les oprateurs classiques (<= et ==). Les mmes conditions
if auraient pu tre testes avec des expressions entre crochets ([), mais les oprateurs
auraient alors t -le et -eq. Nous employons une forme diffrente de linstruction if
la ligne 13, dans la fonction TAILLE_FICHIER. Vous devons y vrifier lexistence du fichier (dont le nom se trouve dans la variable $NF). Ce test est plus simple crire avec
loprateur -e, mais celui nest pas disponible dans les instructions if de style arithmtique (cest--dire, avec des parenthses la place des crochets).
Examinons prsent la fonction DIMINUER et son expression arithmtique :
32
33

function DIMINUER ()
(( LIBRE-=${1:-0}))

En gnral, les fonctions emploient des accolades pour dlimiter leurs corps. Cependant, en bash, toute instruction composite fait laffaire. Dans ce cas, nous choisissons les
doubles parenthses de lvaluation arithmtique, puisque la fonction na que cette opration effectuer. Quelle que soit la valeur fournie sur la ligne de commande dinvocation de DIMINUER, elle sera le premier paramtre positionnel (cest--dire, $1). Nous
soustrayons simplement cette valeur de $LIBRE. Cest pour cette raison que nous avons
employ la syntaxe des expressions arithmtiques (pour pouvoir utiliser loprateur -=).
Voyons de plus prs deux lignes de la fonction TAILLE_FICHIER :
16
17

set -- $(ls -s "$NF")


FZ=$1

Il se passe beaucoup de choses dans ces quelques caractres. Tout dabord, la commande
ls est excute dans un sous-shell (la construction $( )). Loption -s de ls nous donne la
taille, en blocs, du fichier ainsi que son nom. La sortie de la commande est retourne
sous forme de mots sur la ligne de commande de set. Le rle de cette commande est ici
danalyser les mots contenus dans la sortie de ls. Il existe plusieurs manires de procder,
mais vous pouvez retenir cette technique.
Linstruction set -- prend les mots restants sur la ligne de commande et en fait les nouveaux paramtres positionnels. Si vous crivez set -- voici un petit test, alors $1
vaut voici et $3 vaut petit. Les prcdentes valeurs de $1, $2, etc., sont perdues. Cependant, la ligne 12, nous avons enregistr dans $NF le seul paramtre pass la fonction.
Nous pouvons ainsi rutiliser les paramtres positionnels. Nous demandons au shell
den effectuer lanalyse notre place. Nous disposons donc de la taille du fichier dans la
variable $1 (ligne 17). Cela dit, dans cet exemple, puisque lopration est effectue lintrieur dune fonction, seuls les paramtres positionnels de la fonction sont modifis,
non ceux de linvocation du script.
Nous demandons nouveau au shell deffectuer une analyse notre place (ligne 27) :
27
28

set -- $(df /media/mp3 | grep '^/dev/')


LIBRE=$4

La sortie de la commande df indique la taille, en bloc, disponible sur le priphrique.


Nous la passons grep, car nous voulons conserver uniquement les informations sur le
priphrique, sans les lignes den-tte affiches par df. Aprs que bash a dtermin les
arguments, nous pouvons rcuprer la taille de lespace libre sur le priphrique dans
le paramtre $4.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

12.4. Graver un CD

251

Le commentaire en ligne 26 montre une autre manire danalyser la sortie de la commande df. Nous pouvons lenvoyer awk et laisser celui-ci effectuer lanalyse :
26

# LIBRE=$(df /media/mp3 | awk '/^\/dev/ {print $4}')

Grce lexpression place entre les barres obliques, nous demandons awk de prendre
uniquement en compte les lignes commenant par /dev. Le symbole ^ ancre la recherche
au dbut de la ligne et la barre oblique inverse chappe la signification de la barre oblique. Ainsi, lexpression de recherche ne se finit pas ce point et le premier caractre
trouver est une barre oblique.
Quelle solution devez-vous choisir ? Elles impliquent toutes deux linvocation dun programme externe (grep ou awk). En gnral, il existe plusieurs manires de faire la mme
chose (en bash, comme dans la vie) et le choix vous revient. Daprs notre exprience,
nous vous conseillons dopter pour la premire solution qui vous vient lesprit.

Voir aussi

man df ;

man grep ;

man awk ;

la recette 10.4, Dfinir des fonctions, page 211 ;

la recette 10.5, Utiliser des fonctions : paramtres et valeur de retour, page 213 ;

la recette 19.8, Oublier que les tubes crent des sous-shells, page 493.

12.4. Graver un CD
Problme
Lun de vos rpertoires est rempli de fichiers que vous souhaitez graver sur un CD. Devez-vous acheter un logiciel commercial coteux ou pouvez-vous employer le shell et
quelques programmes Open Source ?

Solution
Vous avez simplement besoin de deux logiciels Open Source, mkisofs et cdrecord, et dun
script bash pour fournit les options adquates.
Commencez par placer tous les fichiers copier sur le CD dans une structure arborescente. Le script va lire ce rpertoire, en crer une image au format ISO, puis la graver
sur le CD. Vous avez simplement besoin dun espace disque suffisant et dun peu de
temps.
Il est possible que ce script ne fonctionne pas sur votre systme. Nous
vous le prsentons comme un exemple et non comme un programme
oprationnel pour lenregistrement et la sauvegarde sur un CD.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

252
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

Chapitre 12 Tches utilisateur sous forme de scripts shell


#!/usr/bin/env bash
# bash Le livre de recettes : script_cd
# script_cd - prpare et grave un CD partir d'un rpertoire.
#
# usage : script_cd rp [ pri_cd ]
#
if [[ $# < 1 || $# > 2 ]]
then
echo 'usage : script_cd rp [ pri_cd ]'
exit 2
fi
# Fixer les valeurs par dfaut.
REPSRC=$1
# Votre priphrique peut tre "ATAPI:0,0,0" ou autre.
PERICD=${2:-"ATAPI:0,0,0"}
IMAGEISO=/tmp/cd$$.iso
echo "construire l'image ISO..."
#
# Crer le systme de fichiers ISO.
#
mkisofs $ISOPTS -A "$(cat ~/.cdAnnotation)" \
-p "$(hostname)" -V "$(basename $REPSRC)" \
-r -o "$IMAGEISO" $REPSRC
ETAT=$?
if [ $ETAT -ne 0 ]
then
echo "Erreur. Impossible de crer l'image ISO."
echo "Recherchez la raison, puis supprimez $IMAGEISO."
exit $ETAT
fi
echo "image ISO termine ; gravure du CD..."
exit
# Graver le CD.
VITESSE=8
OPTS="-eject -v fs=64M driveropts=burnproof"
cdrecord $OPTS -speed=$VITESSE dev=${PERICD} $IMAGEISO
ETAT=$?
if [ $ETAT -ne 0 ]
then
echo "Erreur. Impossible de graver le CD."
echo "Recherchez la raison, puis supprimez $IMAGEISO."
exit $ETAT
fi
48
rm -f $IMAGEISO
echo "termin."

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

12.4. Graver un CD

253

Discussion
Examinons les constructions les plus complexes de ce script.
Voici la ligne 17 :
17

IMAGEISO=/tmp/cd$$.iso

Nous construisons un nom de fichier temporaire bas sur la variable $$, qui contient le
numro de notre processus. Tant que ce script est en cours dexcution, il sera le seul
avoir ce numro. Nous obtenons donc un nom unique parmi tous les autres processus
en cours dexcution. (Voyez la recette 14.11, page 304, pour une meilleure solution.)
la ligne 26, nous conservons le code dtat de la commande mkisofs. Les commandes
Unix ou Linux bien crites (ainsi que les scripts bash) retournent 0 en cas de succs et
une valeur diffrente de zro en cas dchec. Nous aurions pu utiliser uniquement la variable $? dans linstruction if de la ligne de 27, mais nous voulons conserver ltat de la
commande mkisofs pour que, en cas derreur, nous puissions la renvoyer comme valeur
de retour du script (ligne 31). Nous procdons de mme avec la commande cdrecord et
sa valeur de retour (lignes 4147).
Les lignes 2325 mritent sans doute quelques explications :
23
24
25

mkisofs $ISOPTS -A "$(cat ~/.cdAnnotation)" \


-p "$(hostname)" -V "$(basename $REPSRC)" \
-r -o "$IMAGEISO" $REPSRC

Ces trois lignes reprsentent une seule ligne de commande de bash. Elles ont t places
sur plusieurs lignes en ajoutant une barre oblique inverse en dernier caractre afin
dchapper la signification normale dune fin de ligne. Veillez donc ne mettre aucune
espace aprs le caractre \ final. Cette ligne de commande invoque trois sous-shells
dont la sortie permet dobtenir la version finale de la commande mkisofs.
Tout dabord, le programme cat est appel afin dafficher le contenu du fichier
.cdAnnotation, qui se trouve dans le rpertoire personnel (~/) de lutilisateur ayant lanc ce script. Lide est de fournir une chane loption -A, qui, daprs la page de manuel de mkisofs, est une chane crite dans len-tte du volume . De manire
similaire, loption -p attend une autre chane, qui donne le nom du prparateur de
limage. Dans cet exemple, nous utilisons le nom de la machine sur laquelle le script
est dmarr, en invoquant hostname dans un sous-shell. Enfin, le nom du volume est
indiqu par le paramtre -V et nous choisissons le nom du rpertoire dans lequel se
trouvent les fichiers. Puisque ce rpertoire est prcis sur la ligne de commande du
script, mais quil inclut probablement un nom de chemin complet, nous utilisons
basename pour retirer cette partie. Par exemple, /usr/local/donnees devient simplement
donnees).

Voir aussi

la recette 14.11, Utiliser des fichiers temporaires scuriss, page 304.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

254

Chapitre 12 Tches utilisateur sous forme de scripts shell

12.5. Comparer deux documents


Problme
Il est facile de comparer deux documents textuels (voir la recette 17.10, page 441). Mais
quen est-il des documents crs partir des logiciels bureautiques ? Puisquils ne sont
pas enregistrs comme du texte, comment pouvez-vous les comparer ? Vous disposez de
deux versions du mme document et vous souhaitez connatre les modifications apportes au contenu. Existe-t-il une solution autre que limpression des deux documents et
leur comparaison page par page ?

Solution
Tout dabord, utilisez un logiciel de bureautique qui vous permet denregistrer vos documents au format ODF (Open Document Format). Cest le cas des suites telles que OpenOffice. Dautres produits commerciaux devraient normalement reconnatre bientt ce
format. Une fois en possession des fichiers ODF, vous pouvez vous servir dun script
pour comparer uniquement leur contenu. Nous insistons sur le terme contenu car les
diffrences de mise en forme constituent un autre problme et, en gnral, le contenu
est llment le plus important pour lutilisateur.
Voici un script bash qui permet de comparer deux fichiers OpenOffice enregistrs au
format ODF (utilisez lextension conventionnelle odt pour indiquer que le document
est de type texte et non une feuille de calcul ou une prsentation).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#!/usr/bin/env bash
# bash Le livre de recettes : diff_oo
# diff_oo -- compare le CONTENU de deux fichiers OpenOffice.
# Ne fonctionne qu'avec des fichiers .odt.
#
function usage_quitter ()
{
echo "usage : $0 fichier1 fichier2"
echo "les deux fichiers doivent tre de type .odt."
exit $1
} >&2
# Vrifier que les deux arguments sont des noms de fichiers
# lisibles se terminant par .odt.
if (( $# != 2 ))
then
usage_quitter 1
fi
if [[ $1 != *.odt || $2 != *.odt ]]
then
usage_quitter 2
fi
if [[ ! -r $1 || ! -r $2 ]]
then

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

12.5. Comparer deux documents


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

usage_quitter 3
fi
BASE1=$(basename "$1" .odt)
BASE2=$(basename "$2" .odt)
# Les dcompresser dans des rpertoires privs.
PRIV1="/tmp/${BASE1}.$$_1"
PRIV2="/tmp/${BASE2}.$$_2"
# Les rendre absolus.
ICI=$(pwd)
if [[ ${1:0:1} == '/' ]]
then
COMPLET1="${1}"
else
COMPLET1="${ICI}/${1}"
fi
if [[ ${2:0:1} == '/' ]]
then
COMPLET2="${2}"
else
COMPLET2="${ICI}/${2}"
fi
# Crer les zones de travail et vrifier le succs.
# N.B. il faut des espaces autour de { et de } et
#
un ; la fin des listes dans {}.
mkdir "$PRIV1" || { echo Impossible de crer $PRIV1 ; exit 4; }
mkdir "$PRIV2" || { echo Impossible de crer $PRIV2 ; exit 5; }
cd "$PRIV1"
unzip -q "$COMPLET1"
sed -e 's/>/>\
/g' -e 's/</\
</g' content.xml > contentwnl.xml
cd "$PRIV2"
unzip -q "$COMPLET2"
sed -e 's/>/>\
/g' -e 's/</\
</g' content.xml > contentwnl.xml
cd $ICI
diff "${PRIV1}/contentwnl.xml" "${PRIV2}/contentwnl.xml"
rm -rf $PRIV1 $PRIV2

[05/03/08]

bash Le livre de recettes

255

Elodie FRITSCH <elodie.fritsch@total.com>

256

Chapitre 12 Tches utilisateur sous forme de scripts shell

Discussion
Pour crire ce script, il fallait savoir que les fichiers OpenOffice sont enregistrs sous forme de fichiers ZIP. Si vous les dcompressez, vous obtenez un ensemble de fichiers XML
qui constituent votre document. Le contenu du document, cest--dire les paragraphes
de texte sans la mise en forme (mais avec les balises XML qui relient le texte sa mise
en forme), se trouve dans lun de ces fichiers. Lide de ce script est de dcompresser
(unzip) les deux documents et de comparer le contenu avec diff, puis de nettoyer lespace
de travail utilis.
Nous faisons galement en sorte que les diffrences soient plus faciles lire. Puisque le
contenu est en XML et quil y a peu de sauts de ligne, le script en ajoute aprs chaque
balise douverture et avant chaque balise de fermeture (celles qui commencent par une
barre oblique, comme dans </ ... >). Bien que cela gnre un grand nombre de lignes
vides, cela permet galement diff de se concentrer sur les diffrences dans le contenu
textuel.
Du point de vue syntaxique, vous avez dj tout vu dans les autres recettes de ce livre,
mais il nest peut-tre pas inutile dexpliquer certains points, simplement pour que vous
compreniez bien le fonctionnement du script.
La ligne 11 redirige la sortie de la fonction shell vers STDERR. En effet, il sagit dun
message daide et non de la sortie normale du programme. En plaant la redirection au
niveau de la dfinition de la fonction, il est inutile de rediriger sparment chaque ligne.
La ligne 37 contient lexpression if [[ ${1:0:1} == '/' ]], qui vrifie si le premier argument commence par une barre oblique. ${1:0:1} est la syntaxe dextraction dune
chane contenue dans une variable. La variable est ${1}, cest--dire le premier paramtre positionnel. La syntaxe :0:1 indique que lextraction doit commencer avec un dcalage gal zro et que la chane extraite ne doit contenir quun seul caractre.
Les lignes 5960 et 6061 sont peut-tre plus difficiles lire car elles appliquent lchappement au caractre de saut de ligne, pour quil fasse partie de la chane de remplacement de sed. Lexpression prend chaque > de la premire substitution et chaque < de la
seconde, en remplaant ce contenu par lui-mme plus un saut de ligne. Ces modifications permettent de placer le code XML et le contenu sur des lignes distinctes. Ainsi, la
commande diff naffiche aucune balise XML, uniquement le texte du contenu.

Voir aussi

la recette 8.7, Dcompresser des fichiers, page 180 ;

la recette 13.3, Analyser du contenu HTML, page 262 ;

la recette 14.11, Utiliser des fichiers temporaires scuriss, page 304 ;

la recette 17.3, Dzipper plusieurs archives ZIP, page 432 ;

la recette 17.10, Utiliser diff et patch, page 441.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13
Analyses et tches
similaires
Les programmeurs reconnatront rapidement les tches de ce chapitre. Les recettes ne
sont pas ncessairement plus labores que les autres scripts bash de cet ouvrage, mais,
si vous ntes pas un programmeur, ces tches pourraient vous sembler obscures ou sans
rapport avec votre utilisation de bash. Nous nallons pas expliquer les raisons des problmes traits ici (en tant que programmeurs, vous les reconnatrez facilement). Mme si
les situations dcrites ne se prsentent pas vous, nhsitez pas les tudier malgr tout
car elles ont plein de choses vous apprendre sur bash.
Certaines solutions de ce chapitre concernent lanalyse des arguments de la ligne de
commande. Vous savez que les options dun script shell sont gnralement indiques
par un signe moins suivi dune seule lettre. Par exemple, une option -q pourrait demander votre script de passer en mode silencieux (quiet) et dafficher moins de messages.
Parfois, une option attend un argument. Par exemple, une option -u pourrait servir
prciser un nom dutilisateur et devrait donc tre suivie de ce nom. Cette distinction va
tre clarifie dans la premire recette de ce chapitre.

13.1. Analyser les arguments dun script


Problme
Vous souhaitez passer des options votre script afin den ajuster le comportement. Vous
pouvez les analyser directement en utilisant ${#}, pour connatre le nombre darguments, et ${1:0:1}, pour tester si le premier caractre du premier argument est un signe
moins. Vous avez alors besoin dune forme de logique if/then ou case pour reconnatre
loption et son argument (si elle en prend un). Et si lutilisateur na pas fourni largument attendu ? Et sil a appel votre script en combinant deux options (par exemple,
-ab) ? Devez-vous galement traiter ce cas ? Lanalyse des options dun script shell est
une tche trs frquente. De nombreux scripts ont des options. Existe-t-il une manire
standard de les analyser ?

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

258

Chapitre 13 Analyses et tches similaires

Solution
Utilisez la commande getopts interne bash pour faciliter lanalyse des options.
Voici un exemple, bas en grande partie sur celui de la page de manuel de getopts :
#!/usr/bin/env bash
# bash Le livre de recettes : exemple_getopts
#
# Utiliser getopts.
#
optiona=
optionb=
while getopts 'ab:' OPTION
do
case $OPTION in
a)
optiona=1
;;
b)
optionb=1
valeurb="$OPTARG"
;;
?)
printf "Usage : %s: [-a] [-b valeur] args\n" $(basename $0) >&2
exit 2
;;
esac
done
shift $(($OPTIND - 1))
if [ "$optiona" ]
then
printf "Option -a donne\n"
fi
if [ "$optionb" ]
then
printf 'Option -b "%s" donne\n' "$valeurb"
fi
printf "Les arguments restants sont : %s\n" "$*"

Discussion
Ce script reconnat deux sortes doptions. La premire, et la plus simple, est une option
donne seule. Elle reprsente gnralement un indicateur qui modifie le comportement dune commande. Cest, par exemple, le cas de loption -l de la commande ls. Une
option de la deuxime sorte prend un argument, par exemple loption -u de la commande mysql. Elle attend quun nom dutilisateur soit indiqu, comme dans mysql -u
sysadmin. Voyons comment getopts analyse ces deux sortes doptions.
La commande getopts prend deux arguments :
getopts 'ab:' OPTION

Le premier prcise la liste des lettres doptions. Le second est le nom dune variable. Dans
notre exemple, -a et -b sont les deux seules options valides et le premier argument de ge[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.1. Analyser les arguments dun script

259

topts contient donc ces deux lettres, ainsi que des deux-points. Que reprsente donc ce
caractre ? Il signifie que -b prend un argument, tout comme -u nomUtilisateur ou -f
nomFichier. Le caractre deux-points doit tre accol toute option attendant un argument. Par exemple, si seule -a prend un argument, nous devons alors crire 'a:b'.
La commande getopts fixe la variable indique dans le deuxime argument la valeur
quelle trouve lors de lanalyse de la liste des arguments du script ($1, $2, etc.). Si elle rencontre un argument commenant par un signe moins, elle le considre comme une option et place la lettre dans la variable indique ($OPTION dans notre exemple). Ensuite, elle
retourne vrai (0) afin que la boucle while qui traite loption puisse poursuivre avec les
autres options en renouvelant des appels getopts jusqu ce quil ny ait plus darguments (ou quelle rencontre un double signe moins --, qui permet aux utilisateurs dindiquer explicitement la fin des options). Ensuite, getopts retourne faux (diffrent de zro)
et la boucle while se termine.
lintrieur de la boucle, pour traiter les lettres doptions, nous employons une instruction case sur la variable $OPTION et fixons la valeur dindicateurs ou effectuons laction
correspondant loption en cours. Lorsque loption prend un argument, celui-ci est plac
dans la variable $OPTARG (un nom fig sans rapport avec $OPTION). Nous devons enregistrer cette valeur en laffectant une autre variable, car lanalyse se poursuit et la variable
$OPTARG est rinitialise chaque invocation de getopts.
Le troisime cas de notre instruction case est un point dinterrogation. Ce motif du
shell correspond tout caractre isol. Lorsque getopts rencontre une option qui ne fait
pas partie de celles attendues ('ab:' dans notre exemple), elle retourne un point dinterrogation littral dans la variable ($OPTION dans notre cas). Notre instruction case
aurait donc pu utiliser \?) ou '?') pour une correspondance exacte, mais ?, en tant que
motif correspondant un seul caractre, est parfaitement un cas par dfaut. Il correspondra au point dinterrogation littral ainsi qu tout autre caractre isol.
Dans le message dutilisation affich, nous apportons deux changements par rapport au
script dexemple de la page de manuel. Tout dabord, nous utilisons $(basename $0)
pour obtenir le nom du script sans le chemin qui pourrait faire partie de son invocation.
Ensuite, nous redirigeons le message vers lerreur standard (>&2) car cest l que doivent
aller de tels messages. Tous les messages derreur mis par getopts, lorsquelle rencontre
une option inconnue ou quun argument est manquant, sont toujours crits sur lerreur
standard. Nous y ajoutons notre message dutilisation.
Aprs la boucle while, la ligne suivante est excute :
shift $(($OPTIND 1))

Elle utilise une instruction shift pour dcaler les paramtres positionnels du script
shell ($1, $2, etc.) dun nombre de positions vers le bas (en supprimant les premiers). La
variable $OPTIND est un indice dans les arguments dont getopts se sert pour indiquer la
position de son analyse. Une fois lanalyse termine, nous pouvons carter toutes les options traites en appelant cette instruction shift. Prenons par exemple la ligne de commande suivante :
monScript -a -b alt rouge vert bleu

Aprs lanalyse des options, $OPTIND a la valeur 4. En procdant un dcalage de trois


($OPTIND-1), nous cartons les options. Un rapide echo $* affiche alors :
rouge vert bleu
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

260

Chapitre 13 Analyses et tches similaires

Les arguments restants (qui ne sont pas des options) sont prts tre employs dans le
script (sans doute dans une boucle for). Dans notre exemple, la dernire ligne est une
instruction printf qui affiche tous les arguments restants.

Voir aussi

help case ;

help getopts ;

help getopt ;

la recette 5.8, Parcourir les arguments dun script, page 96 ;

la recette 5.11, Compter les arguments, page 101 ;

la recette 5.12, Extraire certains arguments, page 103 ;

la recette 6.10, Boucler avec while, page 131 ;

la recette 6.14, Raliser des branchements multiples, page 137 ;

la recette 6.15, Analyser les arguments de la ligne de commande, page 139 ;

la recette 13.2, Afficher ses propres messages derreur lors de lanalyse, page 260.

13.2. Afficher ses propres messages derreur


lors de lanalyse
Problme
Vous utilisez getopts pour analyser les options de votre script shell, mais vous naimez
pas les messages derreur quelle affiche lorsque lentre ne lui convient pas. Pouvezvous continuer utiliser getopts, mais en crivant votre propre gestion des erreurs ?

Solution
Si vous souhaitez que getopts naffiche aucune erreur, donnez simplement la valeur 0
$OPTERR avant de commencer lanalyse. Si vous voulez que getopts vous donne plus dinformations sans les messages derreur, commencez la liste des options par un caractre
deux-points. (Dans les commentaires du script, v--- reprsente une f lche pointant
vers un endroit particulier de la ligne qui se trouve en dessous, dans ce cas pour montrer
le caractre deux-points.)
#!/usr/bin/env bash
# bash Le livre de recettes : getopts_personnalise
#
# Utiliser getopts - avec des messages d'erreur personnaliss
#
optiona=
optionb=
# Puisque getopts ne doit pas gnrer de messages d'erreur,
# mais que ce script doit afficher ses propres messages,

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.2. Afficher ses propres messages derreur lors de lanalyse


# nous commenons la liste des options par un ':' pour
# getopts au silence.
#
v---ici
while getopts :ab: TROUVE
do
case $TROUVE in
a)
optiona=1
;;
b)
optionb=1
valeurb="$OPTARG"
;;
\:) printf "Il manque un argument l'option -%s
printf "Usage : %s: [-a] [-b valeur] args\n"
exit 2
;;
\?)
printf "Option inconnue : -%s\n" $OPTARG
printf "Usage : %s: [-a] [-b valeur] args\n"
exit 2
;;

261
rduire

\n" $OPTARG
$(basename $0)

$(basename $0)

esac >&2
done
shift $(($OPTIND - 1))
if [ "$optiona" ]
then
printf "Option -a donne\n"
fi
if [ "$optionb" ]
then
printf 'Option -b "%s" donne\n' "$valeurb"
fi
printf "Les arguments restants sont : %s\n" "$*"

Discussion
Ce script est trs similaire celui de la recette 13.1, page 257. Reportez-vous sa description pour en comprendre le fonctionnement. Cependant, dans cet exemple, getopts peut
retourner un caractre deux-points. Cela se produit lorsquil manque une option (par
exemple, si vous invoquez le script avec -b sans lui donner dargument). Dans ce cas, la
lettre de loption est place dans $OPTARG afin que vous sachiez quelle est option fautive.
De manire similaire, lorsquune option non reconnue est utilise (par exemple, si vous
ajoutez -d lors de linvocation de notre exemple), getopts retourne un point dinterrogation dans la variable $TROUVE et place la lettre (d dans ce cas) dans la variable $OPTARG,
afin quelle puisse servir dans les messages derreur.
Nous avons plac une barre oblique inverse devant les caractres deux-points et points
dinterrogation pour indiquer quil sagit de littraux et non de motifs ou dune syntaxe
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

262

Chapitre 13 Analyses et tches similaires

particulire du shell. Mme si ce nest pas ncessaire pour les deux-points, il est prfrable de conserver la mme construction pour les deux signes de ponctuation.
Nous avons galement ajout une redirection des entres/sorties la clause esac (la fin
de linstruction case). Ainsi, les diverses instructions printf envoient leur sortie vers lerreur standard. Cest tout fait le rle de lerreur standard et il est plus facile de placer
cette redirection cet endroit quindividuellement sur chaque instruction printf.

Voir aussi

help case ;

help getopts ;

help getopt ;

la recette 5.8, Parcourir les arguments dun script, page 96 ;

la recette 5.11, Compter les arguments, page 101 ;

la recette 5.12, Extraire certains arguments, page 103 ;

la recette 6.15, Analyser les arguments de la ligne de commande, page 139 ;

la recette 13.1, Analyser les arguments dun script, page 257.

13.3. Analyser du contenu HTML


Problme
Vous souhaitez extraire les chanes de caractres dun contenu HTML. Par exemple,
vous aimeriez obtenir les chanes de type href="URL" qui se trouvent dans les balises
<a>.

Solution
Pour une analyse rapide, non toute preuve, dun contenu HTML, vous pouvez essayer les commandes suivantes :
cat $1 | sed -e 's/>/>\
/g' | grep '<a' | while IFS='"' read a b c ; do echo $b; done

Discussion
Lanalyse dun contenu HTML en bash est assez complexe, principalement parce que
bash est trs orient ligne alors que HTML considre les sauts de ligne comme des espaces. Il nest donc pas rare de rencontrer des balises qui occupent plusieurs lignes :
<a href="blah...blah...blah
autre texte >

Il existe galement deux manires dcrire les balises <a>. La premire utilise une balise
de fermeture </a> spare, tandis que la seconde termine la balise douverture <a> par
/>. Par consquent, il est assez difficile danalyser des lignes qui peuvent contenir plu-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.3. Analyser du contenu HTML

263

sieurs balises et des balises qui peuvent occuper plusieurs lignes. Notre technique simple base sur bash nest pas toute preuve.
Voici les diffrentes tapes de notre solution. Tout dabord, nous sparons les diffrentes
balises prsentes sur une ligne en au plus une ligne par balise :
cat fichier | sed -e 's/>/>\
/g'

Juste aprs la barre oblique inverse, il sagit bien dun saut de ligne. Chaque caractre de
fin de balise (>) est remplac par le mme caractre et un saut de ligne. Ainsi, chaque
balise est place sur des lignes spares, peut-tre avec quelques lignes vides supplmentaires. Le g final demande sed deffectuer la recherche et le remplacement de manire
globale, cest--dire plusieurs fois sur une ligne si ncessaire.
La sortie de cette commande est ensuite envoye vers grep afin de garder uniquement
les lignes des balises <a> ou uniquement celles contenant des guillemets :
cat fichier | sed -e 's/>/>\
/g' | grep '<a'

Ou :
cat fichier | sed -e 's/>/>\
/g' | grep '".*"'

Les apostrophes indiquent au shell de prendre les caractres intrieurs tels quels et de
ne pas leur appliquer une expansion. Nous utilisons une expression rgulire qui correspond des guillemets, suivis de tout caractre (.), un nombre quelconque de fois (*),
puis dautres guillemets. (Cela ne fonctionne pas si la chane est elle-mme sur plusieurs
lignes.)
Pour analyser le contenu de lintrieur des guillemets, une astuce consiste employer
la variable $IFS (Internal Field Separator) du shell afin de lui indiquer que les guillemets
(") servent de sparateurs. Vous pouvez galement faire la mme chose avec awk et son
option -F. Par exemple :
cat $1 | sed -e 's/>/>\
/g' | grep '".*"' | awk -F'"' '{ print $2}'

(Ou grep '<a' si vous souhaitez uniquement les balises <a> et non toutes les chanes
entre guillemets.)
La commande suivante sappuie sur $IFS, la place de awk :
cat $1 | sed -e 's/>/>\
/g' | grep '<a' | while IFS='"' read PRE URL POST ; do echo $URL; done

La sortie de grep est envoye dans une boucle while qui lit lentre et la rpartit dans
trois champs (PRE, URL et POST). En faisant prcder la commande read de IFS='"', nous
fixons cette variable denvironnement uniquement pour la commande read et non pour
lintgralit du script. Par consquent, la ligne dentre lue est analyse avec les guillemets comme sparateurs des mots. PRE reoit donc tout ce qui se trouve avant les guillemets, URL tout ce qui se trouve entre les guillemets, et POST tout ce qui vient ensuite.
Pour finir, le script affiche la deuxime variable, URL, cest--dire tous les caractres lintrieur des guillemets.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

264

Chapitre 13 Analyses et tches similaires

Voir aussi

man sed ;

man grep.

13.4. Placer la sortie dans un tableau


Problme
Vous souhaitez que la sortie dun programme ou dun script soit place dans un tableau.

Solution
#!/usr/bin/env bash
# bash Le livre de recettes : analyseParTableau
#
# Dterminer la taille du fichier.
# Utiliser un tableau pour analyser la sortie de ls -l.
LSL=$(ls -ld $1)
declare -a MONTAB
MONTAB=($LSL)
echo Le fichier $1 contient ${MONTAB[4]} octets.

Discussion
Dans notre exemple, nous prenons la sortie de la commande ls -l et plaons ses diffrents mots dans un tableau. Ensuite, nous pouvons simplement faire rfrence chaque
lment du tableau pour obtenir chacun des mots. La sortie de la commande ls -l est
gnralement similaire la suivante (elle peut varier selon vos paramtres rgionaux) :
-rw-r--r--

1 albing users 113 2006-10-10 23:33 mondoc.txt

Si vous connaissez, au moment de lcriture de script, les valeurs placer dans le tableau, il est facile initialiser. Le format est simple. Nous commenons par dclarer une
variable de type tableau, puis nous lui affectons les valeurs :
declare -a MONTAB
MONTAB=(premier deuxieme troisieme quatrieme)

Nous pouvons galement placer une variable lintrieur des parenthses. Il faut simplement ne pas utiliser de guillemets autour de la variable. Linstruction MONTAB=
$("$LSL") place lintgralit de la chane dans le premier lment du tableau puisque
les guillemets en font un tout. ${MYRA[0]} est alors le seul lment du tableau et il contient la chane complte. Ce nest pas ce que nous souhaitons.
Nous pourrions galement raccourcir ce script en combinant les tapes de la manire
suivante :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.5. Analyser la sortie avec une fonction

265

declare -a MONTAB
MONTAB=($(ls -ld $1))

Si vous souhaitez connatre le nombre dlments du nouveau tableau, faites simplement rfrence sa variable : ${#MONTAB[*]} ou ${#MYRA[@]}. Ces deux formes impliquent la saisie de nombreux caractres spciaux.

Voir aussi

la recette 5.19, Utiliser les tableaux, page 111.

13.5. Analyser la sortie avec une fonction


Problme
Vous souhaitez analyser la sortie dun programme en la plaant dans diffrentes variables qui seront utilises par ailleurs dans votre script. Les tableaux sont bien adapts aux
itrations sur les valeurs, mais ne sont pas trs lisibles si vous voulez faire rfrence individuellement chaque lment au lieu dutiliser un indice.

Solution
Utilisez une fonction pour analyser les mots :
#!/usr/bin/env bash
# bash Le livre de recettes : analyseParFonction
#
# Analyser ls -l par un appel de fonction.
# Voici un exemple de la sortie de ls -l :
# -rw-r--r-- 1 albing users 126 2006-10-10 22:50 fichier
function partiesls ()
{
AUTORISATIONS=$1
LIENS=$2
PROPRIETAIRE=$3
GROUPE=$4
TAILLE=$5
DATECREATION=$6
HEURECREATION=$7
FICHIER=$8
}
partiesls $(ls -l "$1")
echo $FICHIER a $LIENS 'lien(s)' et sa taille est de $TAILLE octets.

Voici un exemple dexcution:


$ ./analyseParFonction analyseParFonction
analyseParFonction a 1 lien(s) et sa taille est de 468 octets.
$
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

266

Chapitre 13 Analyses et tches similaires

Discussion
En plaant le texte analyser dans un appel de fonction, nous laissons bash faire le travail. Un appel de fonction est trs similaire un appel de script shell. bash affecte les diffrents mots en arguments $1, $2, etc. Notre fonction prend simplement chaque
paramtre positionnel et les affecte une variable spare. Si les variables ne sont pas
dclares locales, elles sont alors disponibles lintrieur et hors de la fonction.
Nous plaons des guillemets autour de la rfrence $1 dans la commande ls car le nom
de fichier indiqu pourrait comporter des espaces. Les guillemets permettent ls de voir
un seul nom de fichier et non une suite de noms de fichiers spars.
Les apostrophes dans lexpression 'lien(s)' vitent que bash ne traite de manire particulire les parenthses. Nous aurions galement pu placer lintgralit de la phrase (
lexception de la commande echo) entre guillemets ; des guillemets et non des apostrophes pour que la substitution de variables (pour $FICHIER, etc.) ait bien lieu.

Voir aussi

la recette 10.4, Dfinir des fonctions, page 211 ;

la recette 10.5, Utiliser des fonctions : paramtres et valeur de retour, page 213 ;

la recette 13.8, Dterminer le bon accord, page 268 ;

la recette 17.7, Effacer lcran lorsque vous vous dconnectez, page 438.

13.6. Analyser du texte avec read


Problme
Il existe de nombreuses manires danalyser du texte avec bash. Est-il possible demployer autre chose quune fonction ?

Solution
Utilisez linstruction read.
#!/usr/bin/env bash
# bash Le livre de recettes : analyseParRead
#
# Analyser ls -l avec une instruction read.
# Voici un exemple de la sortie de ls -l :
# -rw-r--r-- 1 albing users 126 2006-10-10 22:50 fichier
ls -l "$1" | { read AUTORISATIONS LIENS PROPRIETAIRE GROUPE TAILLE \
DATECREATION HEURECREATION FICHIER ;
echo $FICHIER a $LIENS 'lien(s)' et sa taille est \
de $TAILLE octets. ;
}

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.7. Analyser avec read dans un tableau

267

Discussion
Dans ce script, lanalyse est effectue par read. Cette commande dcompose lentre en
mots, ceux-ci tant spars par des espaces, et affecte chacun deux aux variables indiques. Vous pouvez galement modifier le sparateur, en fixant la variable $IFS (Internal Field Separator) de bash au caractre adquat. Noubliez pas de la remettre sa valeur
initiale !
Comme le montre lexemple de la sortie de ls -l, nous avons choisi des noms significatifs pour chacun des mots. Puisque FICHIER est le dernier mot, tout champ supplmentaire sera inclus dans cette variable. Si le nom du fichier comporte des espaces
comme dans cinquime symphonie de Beethoven , tous ces mots seront placs dans
$FICHIER.

Voir aussi

la recette 2.14, Enregistrer ou runir la sortie de plusieurs commandes, page 44 ;

la recette 19.8, Oublier que les tubes crent des sous-shells, page 493.

13.7. Analyser avec read dans un tableau


Problme
Chaque ligne dentre contient un nombre variable de mots. Vous ne pouvez donc pas
les affecter des variables prdfinies.

Solution
Utilisez loption -a de linstruction read pour placer les mots lus dans une variable de
type tableau :
read -a MONTAB

Discussion
Quelle provienne de lutilisateur ou dun tube, lentre est lue par read et chacun de
ses mots sont placs dans un lment du tableau. Il nest pas ncessaire de dclarer la
variable comme un tableau. Le simple fait de lutiliser ainsi suffit en faire un tableau.
Chaque lment peut tre rfrenc laide de la syntaxe des tableaux de bash, dont le
premier indice commence zro. Par consquent, le deuxime mot de la ligne dentre
se trouve dans ${MONTAB[1]}. Le nombre de mots dtermine la taille du tableau. Vous
pouvez lobtenir laide de ${#MONTAB[@]}.

Voir aussi

la recette 3.5, Lire lentre de lutilisateur, page 64 ;

la recette 13.6, Analyser du texte avec read, page 266.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

268

Chapitre 13 Analyses et tches similaires

13.8. Dterminer le bon accord


Problme
Vous souhaitez accorder un nom en fonction du nombre dobjets. Cependant, vous ne
voulez pas encombrer votre code dinstructions if.

Solution
#!/usr/bin/env bash
# bash Le livre de recettes : auPuriel
#
# Cette fonction met les mots au pluriel en ajoutant un s lorsque
# la valeur ($2) est diffrente de 1 ou gale -1.
# Elle ajoute uniquement un 's' ; elle n'est pas trs intelligente.
#
function pluriel ()
{
if [ $2 -ne 1 -o $2 -eq -1 ]
then
echo ${1}s
else
echo ${1}
fi
}
while read num nom
do
echo $num $(pluriel "$nom" $num)
done

Discussion
La fonction, mme si elle ne fait quajouter un s, fonctionne parfaitement pour de nombreux noms. Elle ne procde aucun contrle derreur sur le nombre ou le contenu des
arguments. Si vous souhaitez employer ce script dans une application relle, vous devrez
ajouter ces vrifications.
Nous plaons le nom entre guillemets lors de lappel la fonction pluriel car il peut
comporter des espaces. En effet, il est fourni par linstruction read et la dernire variable
de cette instruction reoit tout le texte restant sur la ligne dentre. Vous pouvez le constater dans lexemple suivant.
Nous enregistrons le script dans le fichier nomm auPluriel et lexcutons sur les donnes suivantes :
$
1
2
3

cat fichier.entree
poule
canard
oie blanche

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.9. Analyser une chane caractre par caractre

269

4 cheval fougueux
5 ne gris
$
1
2
3
4
5
$

./auPluriel < fichier.entree


poule
canards
oie blanches
cheval fougueuxs
ne griss

Le rsultat contient de nombreuses fautes dorthographe, mais le script se comporte


comme attendu. Si vous prfrez une syntaxe de type C, crivez linstruction if de la
manire suivante :
if (( $2 != 1 || $2 == -1 ))

Le crochet (cest--dire la commande interne test) correspond lancienne forme, plus


courante dans les diffrentes versions de bash, mais les deux solutions doivent fonctionner. Utilisez la syntaxe que vous prfrez.
Nous ne pensons pas que vous allez garder un script comme auPluriel seul. Mais la fonction pluriel pourrait tre utile dans un projet plus important. Ds que vous souhaitez
afficher un nombre de quelque chose, vous pouvez utiliser la fonction pluriel dans la
rfrence, comme lillustre la boucle while prcdente.

Voir aussi

la recette 6.11, Boucler avec read, page 133.

13.9. Analyser une chane caractre par


caractre
Problme
Quelquen soit la raison vous devez analyser une chane caractre par caractre.

Solution
La fonction dextraction dune sous-chane pour les variables vous permet dobtenir les
caractres que vous souhaitez et une autre fonction vous indique la longueur dune
chane :
#!/usr/bin/env bash
# bash Le livre de recettes : unparun
#
# Analyser un caractre de l'entre la fois.
while read UNELIGNE
do

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

270

Chapitre 13 Analyses et tches similaires

for ((i=0; i < ${#UNELIGNE}; i++))


do
UNCAR=${UNELIGNE:i:1}
# Faire quelque chose, par exemple echo $UNCAR
echo $UNCAR
done
done

Discussion
Linstruction read lit depuis lentre standard et place son contenu, une ligne la fois,
dans la variable $UNELIGNE. Puisquil sagit de la seule variable de la commande read,
elle contient lintgralit de la ligne.
La boucle for parcourt chaque caractre de la variable $UNELIGNE. Nous pouvons calculer le nombre ditrations en utilisant ${#UNELIGNE}, qui retourne la longueur du contenu de $UNELIGNE.
Lors de chaque passage dans la boucle, nous affectons UNCAR la valeur dune sous-chane de UNELIGNE. Cette sous-chane est constitue dun caractre et commence la position i. La solution est simple, mais pourquoi aviez-vous ce problme ?

Voir aussi

les autres techniques danalyse de ce chapitre pour savoir sil est possible dviter de
travailler un niveau aussi bas.

13.10. Nettoyer une arborescence SVN


Problme
La commande svn status de Subversion affiche tous les fichiers qui ont t modifis,
mais si larborescence contient galement des fichiers temporaires ou assimils, svn les
inclut galement. Vous souhaitez disposer dun systme de nettoyage de larborescence
source, qui supprime les fichiers inconnus de Subversion.
Tant que vous naurez pas invoqu une commande svn add, Subversion ne connatra pas lexistence des nouveaux fichiers. Ce script ne
doit tre excut quaprs avoir ajout les nouveaux fichiers sources
larborescence ou ils seront supprims.

Solution
svn status src | grep '^\?' | cut -c8- | \
while read nf; do echo "$nf"; rm -rf "$nf"; done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.11. Configurer une base de donnes MySQL

271

Discussion
svn status affiche des listes dont chaque ligne concerne un fichier. La ligne commence
par le caractre M lorsque le fichier a t modifi. Le caractre A reprsente un fichier
nouvellement ajout, mais pas encore valid. Un point dinterrogation signifie que le
fichier est inconnu. laide de la commande grep, nous slectionnons les lignes qui
commencent par un point dinterrogation. Ensuite, nous retirons les huit dernires colonnes de chaque ligne de la sortie afin de ne conserver que le nom du fichier. Nous
lisons les noms de fichiers avec une instruction read dans une boucle while. La commande echo nest pas indispensable, mais elle permet de savoir ce qui est supprim.
Pour la suppression, nous utilisons les options -rf car le fichier peut tre un rpertoire
et nous voulons quelle se fasse en silence. Les problmes, comme ceux provenant des
autorisations, sont carts par loption -f. Elle permet de supprimer le fichier pour
autant que les permissions lautorisent. Nous plaons la rfrence au nom de fichier entre guillemets ("$nf") pour le cas o il contiendrait des caractres spciaux (comme des
espaces).

Voir aussi

la recette 6.11, Boucler avec read, page 133 ;

lannexe D, Gestion de versions, page 575.

13.11. Configurer une base de donnes MySQL


Problme
Vous souhaitez crer et initialiser plusieurs bases de donnes MySQL. Elles sont toutes
initialises avec les mmes commandes SQL. Pour chaque base de donnes, son nom
doit tre prcis, mais elles auront toutes le mme contenu, tout au moins quant linitialisation. Vous devez effectuer cette configuration de nombreuses fois, par exemple
parce quelles sont employes dans des procdures de tests et doivent tre rinitialises
avant le dbut des tests.

Solution
Un simple script bash vous aidera dans cette tche dadministration :
#!/usr/bin/env bash
# bash Le livre de recettes : initbdd
#
# Initialiser des bases de donnes partir d'un fichier standard.
# Crer les bases au besoin.
LISTEBDD=$(mysql -e "SHOW DATABASES;" | tail +2)
select BDD in $LISTEBDD "nouvelle..."
do
if [[ $BDD == "nouvelle..." ]]

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

272

Chapitre 13 Analyses et tches similaires


then
printf "%b" "nom de la nouvelle base : "
read BDD reste
echo cration de la base $BDD
mysql -e "CREATE DATABASE IF NOT EXISTS $BDD;"
fi

if [ "$BDD" ]
then
echo Initialisation de la base : $BDD
mysql $BDD < monInit.sql
fi
done

Discussion
La commande tail +2 permet de retirer les en-ttes de la liste des bases de donnes (voir
la recette 2.12, page 43).
Linstruction select cre un menu affichant les bases de donnes existantes. Nous ajoutons lentre "nouvelle..." (voir les recettes 3.7, page 68, et 6.16, page 142).
Lorsque lutilisateur souhaite crer une nouvelle base de donnes, nous lui demandons
dentrer un nouveau nom. Nous indiquons deux champs la commande read, afin de
mettre en place une petite gestion des erreurs. Si lutilisateur saisit plusieurs noms sur
la ligne, nous prenons uniquement le premier ; il est plac dans la variable $BDD, tandis
que la fin de lentre va dans $reste et est ignore. Nous pourrions vrifier que $reste
est nulle.
Que lutilisateur ait choisi une base parmi la liste ou quil en cre une nouvelle, si la variable $BDD nest pas vide, nous invoquons mysql avec les instructions SQL places dans
le fichier monInit.sql. Celui-ci contient la squence dinitialisation commune.
Si vous souhaitez utiliser un script comme celui-ci, vous devrez peut-tre ajouter des paramtres votre commande mysql, comme -u et -p pour demander la saisie dun nom
dutilisateur et dun mot de passe. Cela dpend de la configuration de votre base de donnes et de ses autorisations, ou de lexistence dun fichier .my.cnf.
Nous pourrions galement ajouter un contrle derreur pour vrifier si la cration de
la nouvelle base de donnes sest bien passe. Dans le cas contraire, il faudrait annuler
la variable BDD afin de ne pas effectuer initialisation. Cependant, comme le propose de
nombreux livre de mathmatiques, nous laissons cet exercice au lecteur.

Voir aussi

la recette 2.12, Sauter len-tte dun fichier, page 43 ;

la recette 3.7, Choisir dans une liste doptions, page 68 ;

la recette 6.16, Crer des menus simples, page 142, pour plus dinformations sur la
commande select ;

la recette 14.20, Utiliser des mots de passe dans un script, page 319.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.12. Extraire certains champs des donnes

273

13.12. Extraire certains champs des donnes


Problme
Vous souhaitez extraire un ou plusieurs champs depuis chaque ligne en sortie.

Solution
Utilisez cut si la ligne contient des dlimiteurs faciles identifier, mme sils sont diffrents au dbut et la fin des champs :
# Exemple simple : utilisateurs, rpertoires personnels et shells
# prsents sur ce systme NetBSD :
$ cut -d':' -f1,6,7 /etc/passwd
root:/root:/bin/csh
toor:/root:/bin/sh
daemon:/:/sbin/nologin
operator:/usr/guest/operator:/sbin/nologin
bin:/:/sbin/nologin
games:/usr/games:/sbin/nologin
postfix:/var/spool/postfix:/sbin/nologin
named:/var/chroot/named:/sbin/nologin
ntpd:/var/chroot/ntpd:/sbin/nologin
sshd:/var/chroot/sshd:/sbin/nologin
smmsp:/nonexistent:/sbin/nologin
uucp:/var/spool/uucppublic:/usr/libexec/uucp/uucico
nobody:/nonexistent:/sbin/nologin
jp:/home/jp:/usr/pkg/bin/bash

# Quel est le shell le plus utilis sur le systme ?


$ cut -d':' -f7 /etc/passwd | sort | uniq -c | sort -rn
10 /sbin/nologin
2 /usr/pkg/bin/bash
1 /bin/csh
1 /bin/sh
1 /usr/libexec/uucp/uucico

# Voyons la liste des deux premiers niveaux de rpertoire :


$ cut -d':' -f6 /etc/passwd | cut -d'/' -f1-3 | sort -u
/
/home/jp
/nonexistent
/root
/usr/games
/usr/guest
/var/chroot
/var/spool

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

274

Chapitre 13 Analyses et tches similaires

Utilisez awk pour un dcoupage selon les espaces ou si vous devez rorganiser les
champs de la sortie. Le symbole reprsente un caractre de tabulation dans la sortie.
Lespace est utilise par dfaut, mais vous pouvez modifier cette configuration en utilisant $OFS :
# Utilisateurs, rpertoires personnels et shells, mais inverser ces
# deux derniers et utiliser une tabulation comme dlimiteur :
$ awk 'BEGIN {FS=":"; OFS="\t"; } { print $1,$7,$6; }' /etc/passwd
root/bin/csh/root
toor/bin/sh/root
daemon/sbin/nologin/
operator/sbin/nologin/usr/guest/operator
bin/sbin/nologin/
games/sbin/nologin/usr/games
postfix/sbin/nologin/var/spool/postfix
named/sbin/nologin/var/chroot/named
ntpd/sbin/nologin/var/chroot/ntpd
sshd/sbin/nologin/var/chroot/sshd
smmsp/sbin/nologin/nonexistent
uucp/usr/libexec/uucp/uucico/var/spool/uucppublic
nobody/sbin/nologin/nonexistent
jp/usr/pkg/bin/bash/home/jp

# Supprimer les multiples espaces et inverser,


# le premier champ est retir :
$ grep '^# [1-9]' /etc/hosts | awk '{print $3,$2}'
10.255.255.255 10.0.0.0
172.31.255.255 172.16.0.0
192.168.255.255 192.168.0.0

Utilisez grep -o pour afficher uniquement la partie qui correspond votre motif. Cette
solution est trs pratique lorsque vous ne pouvez pas prciser les dlimiteurs comme
dans les solutions prcdentes. Par exemple, supposons que vous deviez extraire toutes
les adresses IP dun fichier, quel quil soit. Nous utilisons egrep afin de bnficier des expressions rgulires, mais -o doit fonctionner avec toute variante GNU de grep (elle
nest probablement pas reconnue par les versions non GNU) ; consultez votre documentation.
$ cat mes_adr_ip
Cette ligne 1 contient 1 adresse IP : 10.10.10.10
La ligne 2 en inclut 2 ; elles sont 10.10.10.11 et 10.10.10.12.
Ligne trois, correspondant ftp_server=10.10.10.13:21.
$ egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' mes_adr_ip
10.10.10.10
10.10.10.11
10.10.10.12
10.10.10.13

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.12. Extraire certains champs des donnes

275

Discussion
Les possibilits sont infinies et nous en avons peine vu le dbut. Vous retrouvez ici toute la philosophie des chanes de commandes dUnix. Prenez plusieurs petit outils qui
font trs bien une chose et combinez-les pour rsoudre vos problmes.
Lexpression rgulire utilise pour les adresses IP est trs simple et pourrait correspondre dautres lments, y compris des adresses invalides. Pour un meilleur motif, utilisez les expressions rgulires PCRE (Perl Compatible Regular Expressions) du livre Matrise
des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly), si votre version de grep reconnat loption -P. Sinon, utilisez Perl.
$ grep -oP '([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[05])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])'
mes_adr_ip
10.10.10.10
10.10.10.11
10.10.10.12
10.10.10.13

$ perl -ne 'while ( m/([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[04]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[05])/g ) { print qq($1.$2.$3.$4\n); }' mes_adr_ip


10.10.10.10
10.10.10.11
10.10.10.12
10.10.10.13

Voir aussi

man cut ;

man awk ;

man grep ;

Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) ;

la recette 8.4, Couper des parties de la sortie, page 176 ;

la recette 13.14, Supprimer les espaces, page 277 ;

la recette 15.10, Dterminer mon adresse, page 349 ;

la recette 17.16, Trouver les lignes prsentes dans un fichier mais pas dans un autre, page
456.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

276

Chapitre 13 Analyses et tches similaires

13.13. Actualiser certains champs dans des


fichiers de donnes
Problme
Vous souhaitez extraire certaines parties (champs) dune ligne (enregistrement) et les
actualiser.

Solution
Dans le cas le plus simple, vous souhaitez extraire un seul champ dune ligne, puis lutiliser. Pour cela, vous pouvez vous servir de cut ou de awk (voir la recette 13.12, page 273).
Si vous devez modifier un champ dans un fichier de donnes sans lextraire, le cas est
plus complexe. Pour une simple recherche et remplacement, utilisez sed.
Par exemple, la commande suivante fait passer tous les utilisateurs de csh sh sur ce systme NetBSD :
$ grep csh /etc/passwd
root:*:0:0:Charlie &:/root:/bin/csh
$ sed 's/csh$/sh/' /etc/passwd | grep '^root'
root:*:0:0:Charlie &:/root:/bin/sh

Si le champ est impliqu dans des oprations arithmtiques ou si vous devez modifier
une chane uniquement dans un certain champ, employez awk :
$ cat
Ligne
Ligne
Ligne
Ligne
Ligne

fichier_donnees
1 termine
2 termine
3 termine
4 termine
5 termine

$ awk
Ligne
Ligne
Ligne
Ligne
Ligne

'{print $1, $2+5, $3}' fichier_donnees


6 termine
7 termine
8 termine
9 termine
10 termine

# Si le deuxime champ contient '3', le passer '8' et le marquer.


$ awk '{ if ($2 == "3") print $1, $2+5, $3, "Ajuste" ; else print $0; }'
fichier_donnees
Ligne 1 termine
Ligne 2 termine
Ligne 8 termine Ajuste
Ligne 4 termine
Ligne 5 termine

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.14. Supprimer les espaces

277

Discussion
Les possibilits sont aussi nombreuses que vos donnes, mais les exemples prcdents
vous permettront de comprendre comment modifier facilement vos donnes.

Voir aussi

man awk ;

man sed ;

http://sed.sourceforge.net/sedfaq.html ;

http://sed.sourceforge.net/sed1line.txt ;

la recette 11.7, Calculer avec des dates et des heures, page 233 ;

la recette 13.12, Extraire certains champs des donnes, page 273.

13.14. Supprimer les espaces


Problme
Vous souhaitez supprimer les espaces de dbut et/ou de fin sur les lignes contenant des
champs de donnes.

Solution
Les solutions sappuient sur un traitement de read et de $REPLY spcifique bash. Pour
une autre solution, consultez la fin de la section Discussion.
Tout dabord, voici un fichier dont les lignes contiennent des caractres despacement
au dbut et la fin. Nous avons ajout ~~ afin de les reprer plus facilement. Le symbole
reprsente un caractre de tabulation dans la sortie :
# Montrer les espaces dans notre fichier dexemple :
$ while read; do echo ~~"$REPLY"~~; done < espaces
~~ Cette ligne contient des espaces au dbut.~~
~~Cette ligne contient des espaces la fin. ~~
~~ Cette ligne contient des espaces au dbut et la fin. ~~
~~Tabulation au dbut.~~
~~Tabulation la fin.~~
~~Tabulation au dbut et la fin.~~
~~
Mlange despaces au dbut.~~
~~Mlange despaces la fin.
~~
~~
~~ Mlange despaces au dbut et la fin.

Pour supprimer la fois les espaces de dbut et de fin, utilisez $IFS et ajoutez la variable
interne REPLY (la section Discussion expliquera ce fonctionnement) :
$ while read REPLY; do echo ~~"$REPLY"~~; done < espaces
~~Cette ligne contient des espaces au dbut.~~
~~Cette ligne contient des espaces la fin.~~

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

278

Chapitre 13 Analyses et tches similaires

~~Cette ligne contient des espaces au dbut et la fin.~~


~~Tabulation au dbut.~~
~~Tabulation la fin.~~
~~Tabulation au dbut et la fin.~~
~~Mlange despaces au dbut.~~
~~Mlange despaces la fin.~~
~~Mlange despaces au dbut et la fin.~~

Pour ne supprimer que les espaces, utilisez une correspondance de motifs simple :
# Uniquement les espaces de dbut.
$ while read; do echo "~~${REPLY## }~~"; done < espaces
~~Cette ligne contient des espaces au dbut.~~
~~Cette ligne contient des espaces la fin. ~~
~~Cette ligne contient des espaces au dbut et la fin. ~~
~~Tabulation au dbut.~~
~~Tabulation la fin. ~~
~~Tabulation au dbut et la fin.~~
~~Mlange despaces au dbut.~~
~~Mlange despaces la fin.
~~
~~Mlange despaces au dbut et la fin.
~~
# Uniquement les espaces de fin.
$ while read; do echo "~~${REPLY%% }~~"; done < espaces
~~ Cette ligne contient des espaces au dbut.~~
~~Cette ligne contient des espaces la fin.~~
~~ Cette ligne contient des espaces au dbut et la fin.~~
~~Tabulation au dbut.~~
~~Tabulation la fin. ~~
~~Tabulation au dbut et la fin.~~
~~
Mlange despaces au dbut.~~
~~Mlange despaces la fin.
~~
Mlange despaces au dbut et la fin. ~~
~~

Pour supprimer uniquement les caractres despacement (y compris les tabulations) au


dbut ou la fin, la commande est plus complexe :
# Dans les deux cas, cette commande est ncessaire.
$ shopt -s extglob
# Uniquement les espacements du dbut.
$ while read; do echo "~~${REPLY##+([[:space:]])}~~"; done < espaces
~~Cette ligne contient des espaces au dbut.~~
~~Cette ligne contient des espaces la fin. ~~
~~Cette ligne contient des espaces au dbut et la fin. ~~
~~Tabulation au dbut.~~
~~Tabulation la fin. ~~
~~Tabulation au dbut et la fin.~~
~~Mlange despaces au dbut.~~
~~
~~Mlange despaces la fin.
~~Mlange despaces au dbut et la fin. ~~

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.14. Supprimer les espaces

279

# Uniquement les espacements de fin.


$ while read; do echo "~~${REPLY%%+([[:space:]])}~~"; done < espaces
~~ Cette ligne contient des espaces au dbut.~~
~~Cette ligne contient des espaces la fin.~~
~~ Cette ligne contient des espaces au dbut et la fin.~~
~~Tabulation au dbut.~~
~~Tabulation la fin.~~
~~Tabulation au dbut et la fin.~~
~~
Mlange despaces au dbut.~~
~~Mlange despaces la fin.~~
~~ Mlange despaces au dbut et la fin.~~

Discussion
ce stade, il est fort probable que vous regardiez ces lignes en vous demandant comment nous allons bien pouvoir les rendre comprhensibles. En ralit, lexplication,
bien que subtile, reste simple.
Le premier exemple repose sur la variable $REPLY que read utilise par dfaut lorsque
vous nindiquez pas votre propre variable. Chet Ramey (le responsable de bash) a fait ce
choix de conception : sil ny a pas dautres variables, enregistrer le texte de la ligne lue
dans la variable $REPLY, sans le modifier, sinon lanalyser en utilisant $IFS .
$ while read; do echo ~~"$REPLY"~~; done < espaces

En revanche, lorsque nous passons un ou plusieurs noms de variables read, cette instruction analyse lentre, en utilisant les valeurs de $IFS (qui contient par dfaut une
espace, une tabulation et un saut de ligne). Une phase de ce processus danalyse consiste
retirer les espaces de dbut et de fin :
$ while read REPLY; do echo ~~"$REPLY"~~; done < espaces

Pour supprimer les espaces de dbut ou de fin (non les deux), il suffit demployer les
oprateurs ${##} ou ${%%} (voir la recette 6.7, page 126) :
$ while read; do echo "~~${REPLY## }~~"; done < espaces
$ while read; do echo "~~${REPLY%% }~~"; done < espaces

Cependant, la prise en compte des caractres de tabulation est plus complexe. Si les lignes ne comportaient que des tabulations, nous pourrions utiliser les oprateurs ${##}
ou ${%%} et insrer les caractres de tabulation avec la squence de touches Ctrl-V Ctrl-I.
Malheureusement, nos lignes mlangent espaces et tabulations. Nous activons donc la
globalisation tendue et utilisons une classe de caractres qui clarifie notre intention.
La classe de caractres [:space:] pourrait fonctionner sans extglob, mais nous devons
prciser une ou plusieurs occurrences avec +() pour supprimer plusieurs espaces ou
tabulations (ou combinaisons des deux) sur la mme ligne .
#
$
$
$

Cela fonctionne, mais extglob est ncessaire pour la partie +().


shopt -s extglob
while read; do echo "~~${REPLY##+([[:space:]])}~~"; done < espaces
while read; do echo "~~${REPLY%%+([[:space:]])}~~"; done < espaces

# Cela ne fonctionne pas.


$ while read; do echo "~~${REPLY##[[:space:]]}~~"; done < espaces

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

280

Chapitre 13 Analyses et tches similaires

~~Cette ligne contient des espaces au dbut.~~


~~Cette ligne contient des espaces la fin. ~~
~~Cette ligne contient des espaces au dbut et la fin. ~~
~~Tabulation au dbut.~~
~~Tabulation la fin. ~~
~~Tabulation au dbut et la fin.
~~
~~ Mlange despaces au dbut.~~
~~Mlange despaces la fin.
~~
~~ Mlange despaces au dbut et la fin. ~~

Voici une approche diffrente, qui se fonde galement sur $IFS, mais pour analyser des
champs (ou mots) la place denregistrements (ou lignes) :
$ for i in $(cat autres_espaces); do echo ~~$i~~; done
~~Cette~~
~~ligne~~
~~contient~~
~~un~~
~~espace~~
~~au~~
~~dbut.~~
~~Cette~~
~~ligne~~
~~contient~~
~~un~~
~~espace~~
~~~~
~~la~~
~~fin.~~
~~Cette~~
~~ligne~~
~~contient~~
~~un~~
~~espace~~
~~au~~
~~dbut~~
~~et~~
~~~~
~~la~~
~~fin.~~

Enfin, contrairement nos solutions prcdentes qui sappuient sur le choix de conception de Chet quant linstruction read et la variable $REPLY, le code suivant prend une
toute autre approche :
shopt -s extglob
while IFS= read
# Conserver
echo "Aucun
# Supprimer
echo "Dbut

[05/03/08]

bash Le livre de recettes

-r ligne; do
toutes les espaces.
: ~~$ligne~~"
les espaces de dbut.
: ~~${ligne##+([[:space:]])}~~"

Elodie FRITSCH <elodie.fritsch@total.com>

13.15. Compacter les espaces

281

# Supprimer les espaces de fin.


echo "Fin : ~~${ligne%%+([[:space:]])}~~"
# Supprimer les espaces de dbut et de fin.
ligne="${ligne##+([[:space:]])}"
ligne="${ligne%%+([[:space:]])}"
echo "Tous : ~~$ligne~~"
done < espaces

Voir aussi

la recette 6.7, Tester avec des correspondances de motifs, page 126 ;

la recette 13.6, Analyser du texte avec read, page 266.

13.15. Compacter les espaces


Problme
Un fichier contient des suites despaces et vous souhaitez les compacter afin de navoir
quun seul caractre ou dlimiteur.

Solution
Utilisez tr ou awk, selon les circonstances.

Discussion
Pour transformer une suite despaces en un seul caractre, vous pouvez employer tr,
mais vous risquez dendommager le fichier sil nest pas correctement form. Par exemple, si certains champs sont dlimits par plusieurs espaces mais quils contiennent euxmmes des espaces, le compactage supprimera cette distinction. Dans lexemple suivant,
les caractres _ remplacent les espaces. Le symbole reprsente un caractre de tabulation dans la sortie.
$ cat fichier_donnees
Intitule1
Enr1_Champ1
Enr2_Champ1
Enr3_Champ1

Intitule2
Enr1_Champ2
Enr2_Champ2
Enr3_Champ2

Intitule3
Enr1_Champ3
Enr2_Champ3
Enr3_Champ3

$ cat fichier_donnees | tr -s ' ' '\t'


Intitule1Intitule2Intitule3
Enr1_Champ1Enr1_Champ2Enr1_Champ3
Enr2_Champ1Enr2_Champ2Enr2_Champ3
Enr3_Champ1Enr3_Champ2Enr3_Champ3

Si le dlimiteur de champs est constitu de plusieurs caractres, tr ne fonctionne pas car


les caractres uniques de son premier jeu sont convertis en un caractre unique correspondant du second jeu. Vous pouvez employer awk pour combiner ou convertir des spara-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

282

Chapitre 13 Analyses et tches similaires

teurs de champs. Puisque le sparateur FS interne awk accepte les expressions


rgulires, vous avez une grande libert pour la sparation. Il existe galement une astuce intressante. En cas daffectation dun champ, awk rassemble lenregistrement en
utilisant le sparateur de champs de sortie OFS. Par consquent, si vous affectez un
champ lui-mme et affichez ensuite lenregistrement, vous obtenez le mme rsultat
que si vous aviez remplac FS par OFS sans vous proccuper du nombre denregistrements dans les donnes.
Dans cet exemple, les champs sont spars par plusieurs espaces, mais ils incluent galement des espaces. Par consquent, la commande awk 'BEGIN { OFS = "\t" } { $1
= $1; print }' fichier_donnees1 ne fonctionne pas. Voici le fichier de donnes :
$ cat fichier_donnees1
Intitule1
Enr1 Champ1
Enr2 Champ1
Enr3 Champ1

Intitule2
Enr1 Champ2
Enr2 Champ2
Enr3 Champ2

Intitule3
Enr1 Champ3
Enr2 Champ3
Enr3 Champ3

Dans lexemple suivant, nous affectons deux espaces FS et une tabulation OFS. Nous
procdons ensuite une affectation ($1 = $1) pour que awk reconstruise lenregistrement, mais, puisque les doubles espaces sont remplaces par des tabulations, nous utilisons gsub pour compacter celles-ci, puis nous affichons le rsultat. Le symbole
reprsente un caractre de tabulation dans la sortie. Le rsultat tant plus difficile lire,
nous prsentons galement une version hexadcimale. Noubliez pas que le code ASCII
du caractre de tabulation est 09 et que celui de lespace est 20.
$ awk 'BEGIN { FS = " "; OFS = "\t" } { $1 = $1; gsub(/\t+/, "\t"); print }'
fichier_donnees1
Intitule1Intitule2Intitule3
Enr1 Champ1Enr1 Champ2Enr1 Champ3
Enr2 Champ1Enr2 Champ2Enr2 Champ3
Enr3 Champ1Enr3 Champ2Enr3 Champ3

$ awk 'BEGIN { FS = " "; OFS = "\t" } {


fichier_donnees1 | hexdump -C
00000000 49 6e 74 69 74 75 6c 65 31 09
00000010 6c 65 32 09 49 6e 74 69 74 75
00000020 72 31 20 43 68 61 6d 70 31 09
00000030 68 61 6d 70 32 09 45 6e 72 31
00000040 33 0a 45 6e 72 32 20 43 68 61
00000050 72 32 20 43 68 61 6d 70 32 09
00000060 68 61 6d 70 33 0a 45 6e 72 33
00000070 31 09 45 6e 72 33 20 43 68 61
00000080 72 33 20 43 68 61 6d 70 33 0a
0000008a

$1 = $1; gsub(/\t+/, "\t"); print }'


49
6c
45
20
6d
45
20
6d

6e
65
6e
43
70
6e
43
70

74
33
72
68
31
72
68
32

69
0a
31
61
09
32
61
09

74
45
20
6d
45
20
6d
45

75
6e
43
70
6e
43
70
6e

|Intitule1.Intitu|
|le2.Intitule3.En|
|r1 Champ1.Enr1 C|
|hamp2.Enr1 Champ|
|3.Enr2 Champ1.En|
|r2 Champ2.Enr2 C|
|hamp3.Enr3 Champ|
|1.Enr3 Champ2.En|
|r3 Champ3.|

Vous pouvez galement vous servir de awk pour supprimer les caractres despacement
au dbut et la fin des lignes. Mais, comme nous lavons mentionn prcdemment, les
sparateurs de champs seront galement remplacs sauf sils sont dj des espaces :
# Supprime les caractres despacement au dbut et la fin, mais
# remplace galement les sparateurs de champs TAB par des espaces.
$ awk '{ $1 = $1; print }' espaces
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.16. Traiter des enregistrements de longueur fixe

283

Voir aussi

Effective awk Programming de Arnold Robbins (OReilly Media) ;

sed & awk de Arnold Robbins et Dale Dougherty (OReilly Media) ;

la recette 13.16, Traiter des enregistrements de longueur fixe, page 283 ;

la section Squences dchappement de tr, page 548 ;

la section Tableau des valeurs ASCII, page 555.

13.16. Traiter des enregistrements de longueur


fixe
Problme
Vous devez lire et traiter des donnes qui sont de longueur fixe.

Solution
Utilisez Perl ou gawk 2.13 (ou une version ultrieure). Voici le fichier des donnes :
$ cat fichier_longueur_fixe
Intitule1---------Intitule2-----------------------Intitule3------Enr1 Champ1
Enr1 Champ2
Enr1 Champ3
Enr2 Champ1
Enr2 Champ2
Enr2 Champ3
Enr3 Champ1
Enr3 Champ2
Enr3 Champ3

Vous pouvez traiter son contenu avec gawk de GNU. La variable FIELDWIDTHS doit contenir les diffrentes longueurs des champs. La variable OFS peut avoir la valeur que vous
souhaitez. Vous devez effectuer une affectation afin que gawk reconstruise lenregistrement (voir la recette 13.14, page 277). Cependant, gawk ne supprime pas les espaces qui
servent remplir lenregistrement dorigine. Nous utilisons donc deux commandes
gsubs pour raliser cette opration, la premire pour les premiers champs et la seconde
pour le dernier. Enfin, nous affichons le rsultat. Le symbole reprsente un caractre
de tabulation dans la sortie. Le rsultat tant plus difficile lire, nous prsentons galement une version hexadcimale. Noubliez pas que le code ASCII du caractre de tabulation est 09 et que celui de lespace est 20.
$ gawk ' BEGIN { FIELDWIDTHS = "18 32 16"; OFS = "\t" } { $1 = $1; gsub(/ +\t/,
"\t"); gsub(/ +$/, ""); print }' fichier_longueur_fixe
Intitule1-----------Intitule2-------------------------Intitule3--------Enr1 Champ1Enr1 Champ2Enr1 Champ3
Enr2 Champ1Enr2 Champ2Enr2 Champ3
Enr3 Champ1Enr3 Champ2Enr3 Champ3

$ gawk ' BEGIN { FIELDWIDTHS = "18 32 16"; OFS = "\t" } { $1 = $1; gsub(/ +\t/,
"\t"); gsub(/ +$/, ""); print }' fichier_longueur_fixe | hexdump -C

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

284
00000000
00000010
00000020
00000030
00000040
00000050
00000060
00000070
00000080
00000090
000000a0
000000b0
000000b1

Chapitre 13 Analyses et tches similaires


49
2d
2d
2d
2d
09
31
61
09
33
61
0a

6e
2d
2d
2d
2d
45
20
6d
45
20
6d

74
09
2d
2d
2d
6e
43
70
6e
43
70

69
49
2d
09
2d
72
68
31
72
68
32

74
6e
2d
49
0a
31
61
09
32
61
09

75
74
2d
6e
45
20
6d
45
20
6d
45

6c
69
2d
74
6e
43
70
6e
43
70
6e

65
74
2d
69
72
68
33
72
68
31
72

31
75
2d
74
31
61
0a
32
61
09
33

2d
6c
2d
75
20
6d
45
20
6d
45
20

2d
65
2d
6c
43
70
6e
43
70
6e
43

2d
32
2d
65
68
32
72
68
33
72
68

2d
2d
2d
33
61
09
32
61
0a
33
61

2d
2d
2d
2d
6d
45
20
6d
45
20
6d

2d
2d
2d
2d
70
6e
43
70
6e
43
70

2d
2d
2d
2d
31
72
68
32
72
68
33

|Intitule1-------|
|--.Intitule2----|
|----------------|
|---.Intitule3---|
|----.Enr1 Champ1|
|.Enr1 Champ2.Enr|
|1 Champ3.Enr2 Ch|
|amp1.Enr2 Champ2|
|.Enr2 Champ3.Enr|
|3 Champ1.Enr3 Ch|
|amp2.Enr3 Champ3|
|.|

Si gawk nest pas install sur votre systme, vous pouvez utiliser Perl, qui savre plus
simple. Une boucle while sans affichage lit lentre (-n), dcompose chaque rengistrement ($_) et reconstruit la liste en concatnant les lments laide dun caractre de
tabulation. Chaque enregistrement est affich avec un saut de ligne :
$ perl -ne 'print join("\t", unpack("A18 A32 A16", $_) ) . "\n";'
fichier_longueur_fixe
Intitule1-----------Intitule2-------------------------Intitule3--------Enr1 Champ1Enr1 Champ2Enr1 Champ3
Enr2 Champ1Enr2 Champ2Enr2 Champ3
Enr3 Champ1Enr3 Champ2Enr3 Champ3

$ perl -ne 'print join("\t", unpack("A18


longueur_fixe_file | hexdump -C
00000000 49 6e 74 69 74 75 6c 65 31 2d
00000010 2d 2d 09 49 6e 74 69 74 75 6c
00000020 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d
00000030 2d 2d 2d 09 49 6e 74 69 74 75
00000040 2d 2d 2d 2d 0a 45 6e 72 31 20
00000050 09 45 6e 72 31 20 43 68 61 6d
00000060 31 20 43 68 61 6d 70 33 0a 45
00000070 61 6d 70 31 09 45 6e 72 32 20
00000080 09 45 6e 72 32 20 43 68 61 6d
00000090 33 20 43 68 61 6d 70 31 09 45
000000a0 61 6d 70 32 09 45 6e 72 33 20
000000b0 0a
000000b1

A32 A16", $_) ) . "\n";'


2d
65
2d
6c
43
70
6e
43
70
6e
43

2d
32
2d
65
68
32
72
68
33
72
68

2d
2d
2d
33
61
09
32
61
0a
33
61

2d
2d
2d
2d
6d
45
20
6d
45
20
6d

2d
2d
2d
2d
70
6e
43
70
6e
43
70

2d
2d
2d
2d
31
72
68
32
72
68
33

|Intitule1-------|
|--.Intitule2----|
|----------------|
|---.Intitule3---|
|----.Enr1 Champ1|
|.Enr1 Champ2.Enr|
|1 Champ3.Enr2 Ch|
|amp1.Enr2 Champ2|
|.Enr2 Champ3.Enr|
|3 Champ1.Enr3 Ch|
|amp2.Enr3 Champ3|
|.|

Consultez la documentation de Perl pour plus dinformations sur les formats de pack
et de unpack.

Discussion
Quiconque possde une exprience Unix utilise automatiquement une forme de dlimiteur dans la sortie, puisque les outils textutils ne sont jamais trs loin. Par consquent,
les enregistrements de longueur fixe sont assez rares dans le monde Unix. En revanche,
ils sont trs frquents dans les grands systmes et ils proviennent gnralement dappli-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.17. Traiter des fichiers sans sauts de ligne

285

cations de type SAP. Comme nous venons de le voir, vous pouvez les manipuler sans difficult.
Les solutions donnes ont pour inconvnient dexiger que lenregistrement se termine
par un saut de ligne. Ce nest pas souvent le cas dans les fichiers provenant des grands
systmes. Vous pouvez alors utiliser la recette 13.17, page 285, pour ajouter des sauts de
lignes la fin de chaque enregistrement avant de les traiter.

Voir aussi

man gawk ;

http://www.faqs.org/faqs/computer-lang/awk/faq/ ;

http://perl.enstimac.fr/DocFr/perlfunc.html#item_unpack ;

http://perl.enstimac.fr/DocFr/perlfunc.html#item_pack ;

la recette 13.14, Supprimer les espaces, page 277 ;

la recette 13.17, Traiter des fichiers sans sauts de ligne, page 285.

13.17. Traiter des fichiers sans sauts de ligne


Problme
Vous disposez dun grand fichier qui ne contient aucun saut de ligne et vous devez le
traiter.

Solution
Prtraitez le fichier en ajoutant des sauts de ligne aux endroits adquats. Par exemple,
les fichiers ODF (Open Document Format) dOpenOffice.org sont essentiellement des fichiers XML compresss. Il est possible de les dcompresser (avec unzip) et de traiter le
contenu XML avec grep. La recette 12.5, page 254, dtaille la manipulation de fichiers
ODF. Dans cet exemple, nous insrons un saut de ligne aprs chaque symbole de fermeture (>). Il est ainsi plus facile de traiter le fichier avec grep ou dautres logiciels textutils.
Notez quil faut saisir une barre oblique inverse immdiatement suivie de la touche Entre pour inclure un saut de ligne chapp dans le script sed :
$ wc -l contenu.xml
1 contenu.xml
$ sed -e 's/>/>\
/g' contenu.xml | wc -l
1687

Si les enregistrements sont de longueur fixe, sans saut de ligne, optez pour la solution
suivante, o 48 correspond la longueur de lenregistrement.
$ cat longueur_fixe
Ligne_1_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_2_ _
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_3_ _

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

286

Chapitre 13 Analyses et tches similaires

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_4_ _
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_5_ _
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_6_ _
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_7_ _
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_8_ _
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_9_ _
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_10_
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_11_
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZLigne_12_
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ

wc -l longueur_fixe
1 longueur_fixe

$ sed 's/.\{48\}/&\
/g;' longueur_fixe
Ligne_1_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_2_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_3_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_4_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_5_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_6_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_7_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_8_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_9_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_10_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_11_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_12_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ

$ perl -pe 's/(.{48})/$1\n/g;' longueur_fixe


Ligne_1_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_2_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_3_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_4_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_5_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_6_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_7_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_8_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_9_ _aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_10_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_11_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ
Ligne_12_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZZZ

Discussion
Cette situation se rencontre le plus souvent lorsque les programmeurs gnre une sortie, notamment en utilisant des modules tout faits, en particulier pour du contenu
HTML ou XML.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.18. Convertir un fichier de donnes au format CSV

287

Vous noterez que la syntaxe des substitutions de sed permet dinclure des sauts de ligne.
Dans sed, une esperluette littrale (&) sur le ct droit dune substitution est remplace
par lexpression correspondante sur le ct gauche. La barre oblique inverse finale (\)
sur la premire ligne chappe le saut de ligne afin que le shell laccepte, mais il fait partie
de la partie droite de la substitution de sed. En effet, sed ne reconnat pas \n comme un
mta-caractre lorsquil se trouve dans la partie droite de s///.

Voir aussi

http://sed.sourceforge.net/sedfaq.html ;

Effective awk Programming de Arnold Robbins (OReilly Media) ;

sed & awk de Arnold Robbins et Dale Dougherty (OReilly Media) ;

la recette 12.5, Comparer deux documents, page 254 ;

la recette 13.16, Traiter des enregistrements de longueur fixe, page 283.

13.18. Convertir un fichier de donnes au


format CSV
Problme
Vous souhaitez convertir votre fichier de donnes au format CVS (Comma Separated Values).

Solution
Utilisez awk pour convertir les donnes au format CSV :
$ awk 'BEGIN { FS="\t"; OFS="\",\"" } { gsub(/"/, "\"\"");
"\"%s\"\n", $0}' avec_tab
"Ligne 1","Champ 2","Champ 3","Champ 4 avec ""guillemets""
"Ligne 2","Champ 2","Champ 3","Champ 4 avec ""guillemets""
"Ligne 3","Champ 2","Champ 3","Champ 4 avec ""guillemets""
"Ligne 4","Champ 2","Champ 3","Champ 4 avec ""guillemets""

$1 = $1; printf
internes"
internes"
internes"
internes"

Vous pouvez galement obtenir le mme rsultat avec Perl :


$ perl -naF'\t' -e 'chomp @F; s/"/""/g
@F).qq("\n);' avec_tab
"Ligne 1","Champ 2","Champ 3","Champ 4
"Ligne 2","Champ 2","Champ 3","Champ 4
"Ligne 3","Champ 2","Champ 3","Champ 4
"Ligne 4","Champ 2","Champ 3","Champ 4

for @F; print q(").join(q(","),


avec
avec
avec
avec

""guillemets""
""guillemets""
""guillemets""
""guillemets""

internes"
internes"
internes"
internes"

Discussion
Tout dabord, il nest pas facile de donner une dfinition prcise de CSV. Il nexiste aucune spcification formelle et autant de versions que de fournisseurs. Dans notre cas, la

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

288

Chapitre 13 Analyses et tches similaires

version est trs simple et devrait fonctionner sur tous les systmes. Nous plaons des
guillemets autour de tous les champs (certaines implmentations placent des guillemets
uniquement autour des chanes ou celles contenant des virgules) et nous doublons les
guillemets internes.
Pour cela, nous demandons awk de dcomposer les champs de lentre en utilisant la
tabulation comme sparateur et nous fixons le sparateur de sortie (OFS) ",". Ensuite,
nous remplaons globalement tout guillemet par deux guillemets, nous effectuons une
affectation afin que awk reconstruise lenregistrement (voir la recette 13.14, page 277) et
nous affichons celui-ci avec des guillemets de dbut et de fin. Il nous a fallu chapper
les guillemets en plusieurs endroits. La commande est donc peu lisible, mais elle est relativement simple.

Voir aussi

la FAQ de awk ;

la recette 13.14, Supprimer les espaces, page 277 ;

la recette 13.19, Analyser un fichier CSV, page 288.

13.19. Analyser un fichier CSV


Problme
Vous disposez dun fichier de donnes au format CSV (Comma Separated Values) et vous
souhaitez lanalyser.

Solution
Contrairement la recette prcdente qui convertit un fichier au format CSV, il nexiste
aucune solution simple pour celle-ci. En effet, il est assez difficile de dfinir prcisment
ce que signifie CSV.
Voici les pistes que vous pouvez explorer :

sed : http://sed.sourceforge.net/sedfaq4.html#s4.12 ;

awk : http://lorance.freeshell.org/csv/ ;

Perl : le livre Matrise des expressions rgulires, 2e dition de Jeffrey E. F. Friedl (ditions OReilly) propose une expression rgulire pour cette manipulation ;

Perl : voir CPAN (http://www.cpan.org/) pour les diffrents modules disponibles ;

chargez le fichier CSV dans un tableur (Calc dOpenOffice et Excel de Microsoft


feront parfaitement laffaire), puis copiez et collez le contenu dans un diteur de
texte. Vous devriez obtenir un contenu dlimit par des tabulations que vous pouvez alors manipuler facilement.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

13.19. Analyser un fichier CSV

289

Discussion
Comme nous lavons indiqu la recette 13.18, page 287, il nexiste aucune spcification
formelle de CSV. Combine aux diffrents types de donnes, cette situation rend lanalyse dun fichier CSV plus complique quil ny parat.

Voir aussi

la recette 13.18, Convertir un fichier de donnes au format CSV, page 287.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14
Scripts scuriss

Comment des scripts shell peuvent-ils tre scuriss alors quil est toujours possible den
lire le code source ?
Les systmes qui veulent dissimuler les dtails dimplmentation sappuient sur une scurit par lobscurit, mais cette scurit nest quapparente. Pour sen convaincre, il suffit
simplement dinterroger les fournisseurs de logiciels dont les codes sources sont gards
secrets. Leurs produits nen restent pas moins vulnrables aux attaques dveloppes par
des personnes qui nont jamais eu accs ces sources. loppos, le code source
dOpenSSH et dOpenBSD, qui est totalement disponible, est trs sr.
La scurit par lobscurit ne tiendra pas longtemps, mme si, sous certaines formes, elle
peut apporter un niveau de scurit supplmentaire. Par exemple, lorsque les dmons
coutent sur des numros de ports non standard, les pirates nophytes ont plus de difficults perptrer leurs forfaits. En revanche, la scurit par lobscurit ne doit jamais
tre employe seule car, tt ou tard, quelquun dcouvrira ce que vous cachez.
Comme lexplique Bruce Schneier, la scurit est un processus. Il ne sagit pas dun produit, dun objet ou dune technique, et elle nest jamais termine. Les technologies, les
rseaux, les attaques et les dfenses voluent. Ce doit galement tre le cas de votre systme de scurit. Par consquent, comment peut-on crire des scripts shell scuriss ?
Les scripts shell scuriss raliseront leurs tches de manire fiable et uniquement ces
tches. Ils ne seront pas des portes vers les autorisations de root, ne permettront pas le
lancement accidentel dune commande rm -rf / et ne dvoileront pas des informations
sensibles, comme les mots de passe. Ils seront robustes, mais choueront avec lgance.
Ils tolreront les erreurs de lutilisateur et valideront toutes ses entres. Ils seront aussi
simples que possible et contiendront uniquement du code clair et lisible, ainsi quune
description du fonctionnement de chaque ligne ambigu.
Cette description convient tout programme robuste bien conu. La scurit doit tre
incluse ds le dbut de la conception et non pas ajoute la fin. Dans ce chapitre, nous
prsentons les faiblesses et les problmes de scurit les plus courants, ainsi que leurs
solutions.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

292

Chapitre 14 Scripts scuriss

La littrature concernant la scurit est importante. Si ce sujet vous intresse, vous pouvez commencer par le livre Practical UNIX & Internet Security de Gene Spafford et autres
(OReilly Media). Le chapitre 15 de louvrage Introduction aux scripts shell de Nelson H.F.
Beebe et Arnold Robbins (ditions OReilly) constitue une autre ressource indispensable. Il existe galement de nombreux documents en ligne, comme A Lab engineers
check list for writing secure Unix code http://www.auscert.org.au/render.html?it=1975.
Le code suivant reprend les techniques universelles dcriture dun script scuris. En
les runissant dans un mme fichier, vous pourrez y faire rfrence plus facilement lorsque vous en aurez besoin. Prenez le temps de lire attentivement les recettes correspondant chaque technique afin de bien les comprendre.
#!/usr/bin/env bash
# bash Le livre de recettes : modele_securite
# Dfinir un chemin sr.
PATH='/usr/local/bin:/bin:/usr/bin'
# Il est sans doute dj export, mais mieux vaut s'en assurer.
\export PATH
# Effacer tous les alias. Important : le caractre \ de dbut
# vite le dveloppement des alias.
\unalias -a
# Effacer les commandes mmorises.
hash -r
# Fixer la limite stricte 0 afin de dsactiver les fichiers core.
ulimit -H -c 0 -# Dfinir un IFS sr (cette syntaxe est celle de bash et de ksh93,
# elle n'est pas portable).
IFS=$' \t\n'
# Dfinir une variable umask sre et l'utiliser. Cela n'affecte pas
# les fichiers dj redirigs sur la ligne de commande. 002 donne les
# autorisations 0774, 077 les autorisations 0700, etc.
UMASK=002
umask $UMASK
until [ -n "$rep_temp" -a ! -d "$rep_temp" ]; do
rep_temp="/tmp/prefixe_significatif.${RANDOM}${RANDOM}${RANDOM}"
done
mkdir -p -m 0700 $rep_temp \
|| (echo "FATAL : impossible de crer le rpertoire temporaire" \
"'$rep_temp' : $?"; exit 100)
# Nettoyer au mieux les fichiers temporaires. La variable
# $rep_temp doit tre fixe avant ces instructions et ne doit
# pas tre modifie !
nettoyage="rm -rf $rep_temp"
trap "$nettoyage" ABRT EXIT HUP INT QUIT
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.1. viter les problmes de scurit classiques

293

14.1. viter les problmes de scurit classiques


Problme
Vous souhaitez viter les problmes de scurit classiques dans vos scripts.

Solution
Validez toutes les entres externes, y compris les saisies interactives et celles provenant
des fichiers de configuration. En particulier, nutilisez jamais une instruction eval sur
une entre qui na pas t soigneusement vrifie.
Utilisez des fichiers temporaires scuriss, idalement dans des rpertoires temporaires
scuriss.
Vrifiez que les programmes excutables externes utiliss sont dignes de confiance.

Discussion
Dune certaine manire, cette recette aborde peine la scurit des scripts et des systmes. Nanmoins, elle dcrit les problmes que vous rencontrerez le plus souvent.
La validation des donnes, ou plutt son absence, reprsente un point important de la
scurit dun ordinateur. Elle est lorigine des dbordements de tampons, qui constituent les attaques les plus rpandues. Ces problmes naffectent pas bash de la mme manire que C, mais les concepts sont identiques. En bash, il est plus probable quune
entre non valide contienne une commande du type ; rm -rf / plutt quun dbordement de tampon. Quoi quil en soit, vous devez valider vos donnes !
La concurrence critique constitue galement un autre point important. Elle est li au
problme dun assaillant obtenant la possibilit dcrire dans certains fichiers. Une concurrence critique se produit lorsque deux vnements distincts, ou plus, doivent arriver
dans un certain ordre un certain moment, sans interfrences externes. Le plus souvent, ils donnent un utilisateur non privilgi des accs en lecture et/ou en criture
des fichiers quil ne devrait pas pouvoir manipuler et, par lvation des privilges, lui
apporte des accs root. Une utilisation non scurise des fichiers temporaires est souvent
lorigine de ce type dattaques. Pour lviter, il suffit demployer les fichiers temporaires scuriss, si possible dans des rpertoires temporaires scuriss.
Les utilitaires infests par un cheval de Troie constituent une autre source dattaques.
Tout comme le cheval de Troie, ils ne sont pas ce quils semblent tre. Lexemple classique est la version dtourne de la commande ls, qui fonctionne exactement comme la
commande ls relle, sauf lorsquelle est excute par root. Dans ce cas, elle cre un nouvel utilisateur nomm r00t, avec un mot de passe par dfaut connu de lassaillant, et supprime son fichier excutable (sauto-dtruit). Du ct des scripts, vous pouvez au mieux
dfinir une variable $PATH sre. Du point de vue du systme, de nombreux outils, comme Tripwire et AIDE, peuvent vous aider garantir son intgrit.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

294

Chapitre 14 Scripts scuriss

Voir aussi

http://www.tripwiresecurity.com/ ;

http://www.cs.tut.fi/~rammer/aide.html ;

http://osiris.shmoo.com/.

14.2. viter lusurpation de linterprteur


Problme
Vous souhaitez viter certaines formes dattaques par usurpation avec les accs administrateur (setuid root).

Solution
Ajoutez un seul tiret la fin du shell :
#!/bin/bash -

Discussion
La premire ligne dun script (souvent appele ligne shebang) dsigne linterprteur utilis pour traiter la suite du fichier. Le systme recherche galement une seule option
passe linterprteur indiqu. Certaines attaques exploitent ce fonctionnement. Si
vous passez explicitement un argument, elles sont donc vites. Pour plus de dtails,
consultez le document http://www.faqs.org/faqs/unix-faq/faq/part4/section-7.html.
Nanmoins, en figeant le chemin de bash, vous pourrez rencontrer des problmes de
portabilit. Pour plus dinformations, consultez la recette 15.1, page 334.

Voir aussi

la recette 14.15, crire des scripts setuid ou setgid, page 312 ;

la recette 15.1, Trouver bash de manire portable, page 334.

14.3. Dfinir une variable $PATH sre


Problme
Vous souhaitez tre certain que votre chemin est sr.

Solution
Fixez $PATH une valeur rpute valide au dbut de chaque script :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.3. Dfinir une variable $PATH sre

295

# Dfinir un chemin sr.


PATH='/usr/local/bin:/bin:/usr/bin'
# Il est sans doute dj export, mais mieux vaut s'en assurer.
export PATH

Vous pouvez galement employer getconf pour obtenir un chemin permettant daccder
tous les outils standard (garanti par POSIX) :
export PATH=$(getconf PATH)

Discussion
Lexemple prcdent conduit deux problmes de portabilit. Premirement, `` est
plus portable (mais moins lisible) que $(). Deuximement, lajout de la commande
export sur la mme ligne que laffectation de la variable nest pas toujours pris en charge. var='toto'; export var est plus portable que export var='toto'. Notez galement
quune seule invocation de la commande export est ncessaire pour quune variable
soit exporte vers tous les processus enfants.
Si vous nemployez pas getconf, notre exemple propose un bon chemin initial, mais vous
devrez sans doute lajuster votre environnement ou vos besoins particuliers. Vous
pouvez galement utiliser une version moins portable :
export PATH='/usr/local/bin:/bin:/usr/bin'

Selon les risques de scurit et les besoins, vous pouvez indiquer des chemins absolus.
Cette approche devient rapidement lourde et peut constituer un problme lorsque la
portabilit est importante, car les diffrents systmes dexploitation ne placent pas les
outils aux mmes endroits. Pour limiter ces problmes, utilisez des variables. Si vous
procdez ainsi, noubliez pas de les trier afin de ne pas rpter trois fois la mme commande parce que vous auriez manqu les deux autres instances lors du contrle de la
liste non trie.
Cette mthode a galement pour avantage de prsenter rapidement les outils employs
par le script. Vous pouvez mme ajouter une fonction simple qui vrifie que chaque
outil est disponible et excutable avant que le script neffectue son travail.
#!/usr/bin/env bash
# bash Le livre de recettes : trouver_outils
# export peut tre ncessaire, selon ce que vous faites.
# Chemins relativement fiables.
_cp='/bin/cp'
_mv='/bin/mv'
_rm='/bin/rm'
# Chemins moins universels.
case $(/bin/uname) in
'Linux')
_cut='/bin/cut'
_nice='/bin/nice'
# [...]
;;
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

296

Chapitre 14 Scripts scuriss

'SunOS')
_cut='/usr/bin/cut'
_nice='/usr/bin/nice'
# [...]
;;
# [...]
esac
Faites attention aux noms des variables. Certains programmes, comme
InfoZip, utilisent des variables denvironnement, comme $ZIP et
$UNZIP, pour le passage des paramtres. Par consquent, si vous excutez une commande de type ZIP='/usr/bin/zip', vous risquez de passer plusieurs jours vous demander pourquoi les instructions fonctionnent parfaitement sur la ligne de commande mais pas dans votre script.
Croyez-nous sur parole, nous en avons fait les frais. Noubliez pas non
plus de lire la documentation.

Voir aussi

la recette 6.14, Raliser des branchements multiples, page 137 ;

la recette 6.15, Analyser les arguments de la ligne de commande, page 139 ;

la recette 14.9, Trouver les rpertoires modifiables mentionns dans $PATH, page 300 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303 ;

la recette 15.2, Dfinir une variable $PATH de type POSIX, page 335 ;

la recette 16.3, Modifier dfinitivement $PATH, page 376 ;

la recette 16.4, Modifier temporairement $PATH, page 377 ;

la recette 19.3, Oublier que le rpertoire de travail nest pas dans $PATH, page 488 ;

la section Commandes internes et mots rservs, page 508.

14.4. Effacer tous les alias


Problme
Vous souhaitez vous assurer quaucun alias malveillant ne se trouve dans votre environnement.

Solution
Utilisez la commande \unalias -a pour effacer tous les alias existants.

Discussion
Si un assaillant parvient faire excuter une commande root ou un autre utilisateur,
il peut russir obtenir un accs des donnes ou des privilges qui lui sont interdits.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.5. Effacer les commandes mmorises

297

Une manire de procder consiste crer un alias dun autre programme commun (par
exemple ls).
Le caractre \ plac au dbut de la commande permet dviter le dveloppement des
alias. Il est trs important car il empche des comportements comme les suivants :
$ alias unalias=echo
$ alias builtin=ls
$ builtin unalias vi
ls: unalias: Aucun fichier ou rpertoire de ce type
ls: vi: Aucun fichier ou rpertoire de ce type
$ unalias -a
-a

Voir aussi

la recette 10.7, Redfinir des commandes avec des alias, page 219 ;

la recette 10.8, Passer outre les alias ou les fonctions, page 221 ;

la recette 16.6, Raccourcir ou modifier des noms de commandes, page 385.

14.5. Effacer les commandes mmorises


Problme
Vous souhaitez vrifier que la mmoire des commandes na pas t dtourne.

Solution
Utilisez la commande hash -r pour effacer les commandes mmorises.

Discussion
Lors de lexcution des commandes, bash mmorise lemplacement de celles qui se
trouvent dans la variable $PATH afin dacclrer les invocations ultrieures.
Si un assaillant parvient faire excuter une commande root ou un autre utilisateur,
il peut russir obtenir un accs des donnes ou des privilges qui lui sont interdits.
Une manire de procder consiste modifier la mmoire des commandes afin que le
programme souhait soit excut.

Voir aussi

la recette 14.9, Trouver les rpertoires modifiables mentionns dans $PATH, page 300 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303 ;

la recette 15.2, Dfinir une variable $PATH de type POSIX, page 335 ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

298

Chapitre 14 Scripts scuriss

la recette 16.3, Modifier dfinitivement $PATH, page 376 ;

la recette 16.4, Modifier temporairement $PATH, page 377 ;

la recette 19.3, Oublier que le rpertoire de travail nest pas dans $PATH, page 488.

14.6. Interdire les fichiers core


Problme
Vous souhaitez empcher que votre script cre un fichier core en cas derreur non rcuprable. En effet, ces fichiers peuvent contenir des informations sensibles, comme des
mots de passe, provenant de la mmoire.

Solution
Utilisez la commande interne ulimit pour fixer la taille des fichiers core 0, en gnral
dans votre fichier .bashrc :
ulimit -H -c 0 --

Discussion
Les fichiers core sont employs pour le dbogage et constituent une image de la mmoire du processus au moment du dysfonctionnement. Par consquent, ils contiennent
tout ce que le processus avait stock en mmoire, par exemple les mots de passe saisis
par lutilisateur.
La commande prcdente peut tre place dans un fichier systme, comme /etc/profile
ou /etc/bashrc, que les utilisateurs ne peuvent modifier.

Voir aussi

help ulimit.

14.7. Dfinir une variable $IFS sre


Problme
Vous souhaitez que votre variable denvironnement IFS (Internal Field Separator) soit
correcte.

Solution
Fixez-la un tat reconnu au dbut de chaque script en utilisant la syntaxe suivante
(non compatible POSIX) :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.8. Dfinir un umask sr

299

# Dfinir un IFS sr (cette syntaxe est celle de bash et de ksh93,


# elle n'est pas portable).
IFS=$' \t\n'

Discussion
Comme nous le signalons, cette syntaxe nest pas portable. Cependant, la version portable nest pas fiable car elle peut tre facilement modifie par les diteurs qui suppriment
les espaces. En gnral, les valeurs sont lespace, la tabulation et le saut de ligne ; lordre
est important. $*, qui retourne tous les paramtres positionnels, les remplacements de
paramtres spciaux ${!prfixe@} et ${!prfixe*}, ainsi que la compltion programmable, utilisent tous la premire valeur de $IFS comme sparateur.
La mthode dcriture classique laisse une espace et une tabulation la fin de la premire ligne :
1
2

IFS='&#182;
'

Lordre saut de ligne, espace, puis tabulation est moins sujet aux suppressions, mais peut
conduire des rsultats inattendus avec certaines commandes :
1
2

IFS='&#182;
'

Voir aussi

la recette 13.14, Supprimer les espaces, page 277.

14.8. Dfinir un umask sr


Problme
Vous souhaitez dfinir un umask fiable.

Solution
Utilisez la commande interne umask pour dfinir un tat reconnu au dbut de chaque
script :
# Dfinir une variable umask sre et l'utiliser. Cela n'affecte pas
# les fichiers dj redirigs sur la ligne de commande. 002 donne les
# autorisations 0774, 077 les autorisations 0700, etc.
UMASK=002
umask $UMASK

Discussion
Nous dfinissons une variable $UMASK car nous pourrions avoir besoin de masques diffrents dans le programme. Vous pouvez parfaitement vous en passer :
umask 002

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

300

Chapitre 14 Scripts scuriss

Noubliez pas que umask est un masque qui prcise les bits retirer de
lautorisation par dfaut (777, pour les rpertoires, et 666, pour les
fichiers). En cas de doutes, faites des tests :
# Dmarrer un nouveau shell afin de ne pas perturber
# lenvironnement actuel.
/tmp$ bash
# Vrifier la configuration en cours.
/tmp$ touch umask_actuel
# Vrifier dautres configurations.
/tmp$ umask 000 ; touch umask_000
/tmp$ umask 022 ; touch umask_022
/tmp$ umask 077 ; touch umask_077
/tmp$ ls -l umask_*
-rw-rw-rw- 1 jp jp 0
-rw-r--r-- 1 jp jp 0
-rw------- 1 jp jp 0
-rw-rw-r-- 1 jp jp 0

2007-07-30
2007-07-30
2007-07-30
2007-07-30

12:23
12:23
12:23
12:23

umask_000
umask_022
umask_077
umask_actuel

# Nettoyer et quitter le sous-shell.


/tmp$ rm umask_*
/tmp$ exit

Voir aussi

help umask ;

http://linuxzoo.net/page/sec_umask.html.

14.9. Trouver les rpertoires modifiables


mentionns dans $PATH
Problme
Vous souhaitez vous assurer que la variable $PATH de root ne contient aucun rpertoire
modifiable par tous les utilisateurs. Pour connatre les raisons de cette exigence, lisez la
recette 14.10, page 303.

Solution
Le simple script suivant permet de vrifier la variable $PATH. Invoquez-le avec su - ou
sudo pour vrifier les chemins des autres utilisateurs :
#!/usr/bin/env bash
# bash Le livre de recettes : verifier_path.1
# Vrifier si la variable $PATH contient des rpertoires inexistants ou
# modifiables par tous les utilisateurs.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.9. Trouver les rpertoires modifiables mentionns dans $PATH

301

code_sortie=0
for rep in ${PATH//:/ }; do
[ -L "$rep" ] && printf "%b" "lien symbolique, "
if [ ! -d "$rep" ]; then
printf "%b" "manquant\t\t"
(( code_sortie++ ))
elif [ "$(ls -lLd $rep | grep '^d.......w. ')" ]; then
printf "%b" "modifiable par tous les utilisateurs\t"
(( code_sortie++ ))
else
printf "%b" "ok\t\t"
fi
printf "%b" "$rep\n"
done
exit $code_sortie

Par exemple :
# ./verfier_path.1
ok
/usr/local/sbin
ok
/usr/local/bin
ok
/sbin
ok
/bin
ok
/usr/sbin
ok
/usr/bin
ok
/usr/X11R6/bin
ok
/root/bin
manquant
/inexistant
modifiable par tous les utilisateurs /tmp
lien symbolique, modifiable par tous les utilisateurs /tmp/bin
lien symbolique, ok
/root/sbin

Discussion
Nous convertissons le contenu de la variable $PATH en une liste spare par des espaces
grce une technique dcrite la recette 9.11, page 202. Chaque rpertoire est ensuite
compar un lien symbolique (-L) et son existence est vrifie (-d). Puis, nous gnrons
une longue liste (-l) des rpertoires, en drfrenant les liens symboliques (-L) et en
ne gardant que les noms des rpertoires (-d), sans leur contenu. Enfin, nous dterminons les rpertoires modifiables par tous les utilisateurs laide de grep.
Comme vous pouvez le constater, nous espaons les rpertoires ok, tandis que ceux
ayant un problme peuvent tre plus resserrs. Dautre part, nous ne respectons pas la
rgle habituelle des outils Unix, qui restent silencieux except en cas de problme, car
nous estimons quil est intressant de savoir ce qui se trouve dans le chemin, en plus de
la vrification automatique.
Lorsquaucun problme na t dtect dans la variable $PATH, le code de sortie a la valeur zro. Dans le cas contraire, il comptabilise le nombre derreurs trouves. En modifiant lgrement ce code, nous pouvons ajouter le mode, le propritaire et le groupe du
fichier. Ces informations peuvent galement tre intressantes contrler :
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

302

Chapitre 14 Scripts scuriss

#!/usr/bin/env bash
# bash Le livre de recettes : verifier_path.2
# Vrifier si la variable $PATH contient des rpertoires inexistants ou
# modifiables par tous les utilisateurs, avec des statistiques.
code_sortie=0
for rep in ${PATH//:/ }; do
[ -L "$rep" ] && printf "%b" "lien symbolique, "
if [ ! -d "$rep" ]; then
printf "%b" "manquant\t\t\t\t"
(( code_sortie++ ))
else
stat=$(ls -lHd $rep | awk '{print $1, $3, $4}')
if [ "$(echo $stat | grep '^d.......w. ')" ]; then
printf "%b" "modifiable par tous les utilisateurs\t$stat "
(( code_sortie++ ))
else
printf "%b" "ok\t\t$stat "
fi
fi
printf "%b" "$rep\n"
done
exit $code_sortie

Par exemple :
# ./verifier_path.2 ; echo $?
ok
drwxr-xr-x root root /usr/local/sbin
ok
drwxr-xr-x root root /usr/local/bin
ok
drwxr-xr-x root root /sbin
ok
drwxr-xr-x root root /bin
ok
drwxr-xr-x root root /usr/sbin
ok
drwxr-xr-x root root /usr/bin
ok
drwxr-xr-x root root /usr/X11R6/bin
ok
drwx------ root root /root/bin
manquant
/inexistant
modifiable par tous les utilisateurs drwxrwxrwt root root /tmp
lien symbolique, ok
drwxr-xr-x root root /root/sbin
2

Voir aussi

la recette 9.11, Retrouver un fichier partir dune liste demplacements possibles, page
202 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303 ;

la recette 15.2, Dfinir une variable $PATH de type POSIX, page 335 ;

la recette 16.3, Modifier dfinitivement $PATH, page 376 ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.10. Ajouter le rpertoire de travail dans $PATH

la recette 16.4, Modifier temporairement $PATH, page 377 ;

la recette 19.3, Oublier que le rpertoire de travail nest pas dans $PATH, page 488.

303

14.10. Ajouter le rpertoire de travail dans


$PATH
Problme
Vous ne voulez plus saisir ./script pour excuter le script qui se trouve dans le rpertoire de travail et prfrez simplement ajouter . (ou un rpertoire vide, cest--dire un
caractre : initial ou final, ou bien :: au milieu) la variable $PATH.

Solution
Nous dconseillons cette configuration pour nimporte quel utilisateur et recommandons de la bannir pour root. Si vous devez absolument ajouter le rpertoire de travail
la variable $PATH, vrifiez que . se trouve en dernier. Ne le faites jamais en tant que root.

Discussion
Comme vous le savez, le shell examine les rpertoires indiqus dans $PATH lorsque vous
entrez le nom dune commande sans prciser son chemin. La raison de ne pas ajouter .
est la mme que celle dinterdire les rpertoires modifiables par tous les utilisateurs
dans la variable $PATH.
Supposons que le rpertoire de travail soit /tmp et que . se trouve au dbut de $PATH. Si
vous saisissez ls et que le fichier /tmp/ls existe, cest celui-ci qui est excut et non /bin/ls.
Quelles peuvent tre les consquences ? Il est possible que /tmp/ls soit un script malveillant et, si vous lavez excut en tant que root, personne ne peut dire ce qui va se passer. Il peut mme aller jusqu se supprimer lui-mme une fois la trace de ses forfaits
efface.
Que se passe-t-il si . arrive en dernier ? Vous est-il dj arriv, comme nous, de saisir
mc la place de mv ? moins que Midnight Commander ne soit install sur votre systme, vous pouvez alors excuter ./mc alors que vous vouliez /bin/mv. Les rsultats peuvent tre identiques au cas prcdent.
En rsum, najoutez pas . la variable $PATH !

Voir aussi

la section 2.13 de http://www.faqs.org/faqs/unix-faq/faq/part2/ ;

la recette 9.11, Retrouver un fichier partir dune liste demplacements possibles, page
202 ;

la recette 14.3, Dfinir une variable $PATH sre, page 294 ;

la recette 14.9, Trouver les rpertoires modifiables mentionns dans $PATH, page 300 ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

304

Chapitre 14 Scripts scuriss

la recette 15.2, Dfinir une variable $PATH de type POSIX, page 335 ;

la recette 16.3, Modifier dfinitivement $PATH, page 376 ;

la recette 16.4, Modifier temporairement $PATH, page 377 ;

la recette 19.3, Oublier que le rpertoire de travail nest pas dans $PATH, page 488.

14.11. Utiliser des fichiers temporaires


scuriss
Problme
Vous devez crer un fichier ou un rpertoire temporaire, mais tes soucieux des implications dun nom prvisible sur la scurit.

Solution
La solution la plus simple et gnralement satisfaisante consiste employer $RANDOM
dans le script. Par exemple :
# Vrifier que $TMP est dfinie.
[ -n "$TMP" ] || TMP='/tmp'
# Crer un rpertoire temporaire alatoire "satisfaisant".
until [ -n "$rep_temp" -a ! -d "$rep_temp" ]; do
rep_temp="/tmp/prefixe_significatif.${RANDOM}${RANDOM}${RANDOM}"
done
mkdir -p -m 0700 $rep_temp \
|| ( echo "FATAL : impossible de crer le rpertoire temporaire" \
"'$rep_temp' : $?"; exit 100 )

# Crer un fichier temporaire alatoire "satisfaisant".


until [ -n "$fichier_temp" -a ! -e "$fichier_temp" ]; do
fichier_temp="/tmp/prefixe_significatif.${RANDOM}${RANDOM}${RANDOM}"
done
touch $fichier_temp && chmod 0600 $fichier_temp
|| ( echo "FATAL : impossible de crer le fichier temporaire" \
"'$fichier_temp' : $?"; exit 101 )

Mieux encore, vous pouvez utiliser un rpertoire temporaire et un nom de fichier


alatoires !
# bash Le livre de recettes : creer_temp
# Crer un rpertoire temporaire alatoire "satisfaisant".
until [ -n "$rep_temp" -a ! -d "$rep_temp" ]; do
rep_temp="/tmp/prefixe_significatif.${RANDOM}${RANDOM}${RANDOM}"
done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.11. Utiliser des fichiers temporaires scuriss

305

mkdir -p -m 0700 $rep_temp \


|| ( echo "FATAL : impossible de crer le rpertoire temporaire" \
"'$rep_temp' : $?"; exit 100 )
# Crer un fichier temporaire alatoire "satisfaisant" dans le
# rpertoire temporaire.
fichier_temp="$rep_temp/prefixe_significatif.${RANDOM}${RANDOM}${RANDOM}"
touch $fichier_temp && chmod 0600 $fichier_temp \
|| ( echo "FATAL : impossible de crer le rpertoire temporaire" \
"'$fichier_temp' : $?"; exit 101 )

Quelle que soit la manire dont vous procdez, noubliez pas de dfinir un gestionnaire
de signaux afin dassurer le nettoyage. Comme nous lavons not, $rep_temp doit tre
dfini avant que ce gestionnaire soit dclar et sa valeur ne doit pas changer. Si ces
points ne sont pas respects, modifiez le code afin de ladapter vos besoins.
# bash Le livre de recettes : nettoyer_temp
# Nettoyer au mieux les fichiers temporaires. La variable
# $rep_temp doit tre fixe avant ces instructions et ne doit
# pas tre modifie !
nettoyage="rm -rf $rep_temp"
trap "$nettoyage" ABRT EXIT HUP INT QUIT

Discussion
$RANDOM existe depuis bash-2.0 et savre souvent suffisante. Un code simple est prfrable et est plus facile scuriser quun code complexe. Ainsi, lemploi de $RANDOM peut
rendre votre code plus sr sans avoir prendre en charge les complexits de validation
et de vrification des erreurs de mktemp ou de /dev/urandom. Sa simplicit joue en sa faveur. Cependant, $RANDOM ne fournit que des nombres. mktemp gnre des nombres et
des lettres majuscules et minuscules, et urandom produit des nombres et des lettres minuscules. Ces deux outils largissent normment lespace des cls.
Quelle que soit la manire dont il est cr, un rpertoire de travail temporaire prsente
les avantages suivants :

mkdir -p -m 0700 $rep_temp vite la concurrence critique inhrente touch


$fichier_temp && chmod 0600 $fichier_temp ;

les fichiers crs lintrieur du rpertoire ne sont pas visibles un assaillant nonroot lorsque ce rpertoire possde les autorisations 0700 ;

avec un rpertoire temporaire, il est plus facile de sassurer que tous les fichiers
temporaires sont supprims lorsquils sont devenus inutiles. Si les fichiers temporaires sont parpills, il est trs facile den oublier un lors du nettoyage ;

vous pouvez choisir des noms significatifs pour les fichiers temporaires de ce rpertoire, ce qui facilite le dveloppement et le dbogage et amliore la scurit et la
robustesse du script ;

lutilisation dun prfixe significatif dans le chemin indique clairement les scripts
en excution (cette option peut tre bonne ou mauvaise, mais sachez que ps et /proc
font de mme). Par ailleurs, elle peut permettre dindiquer que le nettoyage dun
script a chou et donc viter des fuites dinformations.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

306

Chapitre 14 Scripts scuriss

Le code prcdent conseille dutiliser un prefixe_significatif dans le nom de chemin cr.


Certains dveloppeurs prtendent que cela rduit la scurit puisque ce nom est prvisible. Cette partie du chemin est effectivement prvisible, mais nous pensons que les
avantages apports surpassent cette objection. Si vous ntes pas daccord, omettez simplement le prfixe significatif.
En fonction des risques et de vos besoins scuritaires, vous prfrerez peut-tre utiliser
des fichiers temporaires alatoires lintrieur du rpertoire temporaire alatoire, comme nous lavons fait prcdemment. Cela namliore probablement pas la scurit, mais
si cela vous rassure, procdez de cette manire.
Nous avons mentionn lexistence dune concurrence critique dans la commande touch
$fichier_temp && chmod 0600 $fichier_temp. Voici une manire de lviter :
umask_memorise=$(umask)
umask 077
touch $fichier_temp
umask $umask_memorise
unset umask_memorise

Nous vous conseillons dutiliser un rpertoire temporaire alatoire ainsi quun nom de
fichier alatoire (ou semi-alatoire) puisque les avantages sont plus nombreux.
Si la nature uniquement numrique de $RANDOM vous ennuie, vous pouvez combiner
dautres sources de donnes pseudo-imprvisibles et pseudo-alatoires avec une fonction de hachage :
longue_chaine_aleatoire=$( (last ; who ; netstat -a ; free ; date \
; echo $RANDOM) | md5sum | cut -d' ' -f1 )
Nous vous dconseillons cette mthode car la complexit supplmentaire est probablement un remde pire que le mal. Nanmoins, elle
permet de voir que les choses peuvent tre rendues beaucoup plus
complexes quil est ncessaire.

Une approche thoriquement plus sre consiste employer lutilitaire mktemp prsent
sur de nombreux systmes modernes, avec un repli sur /dev/urandom, galement disponible sur de nombreux systmes rcents, ou mme $RANDOM. Cependant, mktemp et
/dev/urandom ne sont pas toujours disponibles et la prise en compte de ce problme de
manire portable est beaucoup plus complexe que notre solution.
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Tenter de crer un nom de fichier ou un rpertoire temporaire scuris.
# Usage : $fichier_temp=$(CreerTemp <fichier|rep> [chemin/vers/prfixe])
# Retourne le nom alatoire dans NOM_TEMP.
# Par exemple :
#
$rep_temp=$(CreerTemp rep /tmp/$PROGRAMME.foo)
#
$fichier_temp=$(CreerTemp fichier /tmp/$PROGRAMME.foo)
#
function CreerTemp {
# Vrifier que $TMP est dfinie.
[ -n "$TMP" ] || TMP='/tmp'

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.11. Utiliser des fichiers temporaires scuriss

307

local nom_type=$1
local prefixe=${2:-$TMP/temp} # Si le prfixe nest pas indiqu,
# utiliser $TMP + temp.
local type_temp=''
local controle=''
case $nom_type in
fichier )
type_temp=''
ur_cmd='touch'
#
Fichier normal Lisible
Mappartenant
controle='test -f $NOM_TEMP -a -r $NOM_TEMP -a
-a -O $NOM_TEMP'
;;
rep|repertoire )
type_temp='-d'
ur_cmd='mkdir -p -m0700'
#
Rpertoire
Lisible
Parcourable
Mappartenant
controle='test -d $NOM_TEMP -a -r $NOM_TEMP -a
-a -x $NOM_TEMP -a -O $NOM_TEMP'
;;
* ) Error "\nType erron dans $PROGRAMME:CreerTemp
fichier|rep." 1 ;;
esac

Modifiable
-w $NOM_TEMP

Modifiable
-w $NOM_TEMP

! Prciser

# Tout dabord, essayer mktemp.


NOM_TEMP=$(mktemp $type_temp ${prefixe}.XXXXXXXXX)
# En cas dchec, essayer urandom. Si cela choue, abandonner.
if [ -z "$NOM_TEMP" ]; then
NOM_TEMP="${prefixe}.$(cat /dev/urandom | od -x | tr -d ' ' | head
-1)"
$ur_cmd $NOM_TEMP
fi
# Vrifier que le fichier ou le rpertoire a bien t cr.
# Sinon, quitter.
if ! eval $controle; then
Error "\aERREUR FATALE : impossible de crer $nom_type avec
'$0:CreerTemp $*'!\n" 2
else
echo "$NOM_TEMP"
fi
} # Fin de la fonction CreerTemp.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

308

Chapitre 14 Scripts scuriss

Voir aussi

man mktemp ;

la recette 14.13, Fixer les autorisations, page 310 ;

lannexe B, Exemples fournis avec bash, page 559, en particulier le script ./scripts.
noah/mktmp.bash.

14.12. Valider lentre


Problme
Vous attendez une entre (provenant, par exemple, dun utilisateur ou dun programme) et, pour assurer la scurit ou lintgrit des donnes, vous devez vrifier que vous
avez obtenu ce que vous aviez demand.

Solution
Il existe diffrentes manires de valider lentre, en fonction de sa nature et de lexactitude souhaite.
Pour les cas simples de type elle convient ou ne convient pas , utilisez les correspondances de motifs (voir les recettes 6.6, page 124, 6.7, page 126, et 6.8, page 127).
[[ "$entree_brute" == *.jpg ]] && echo "Fichier JPEG reu."

Lorsque plusieurs possibilits sont valides, employez une instruction case (voir les recettes 6.14, page 137, et 6.15, page 139).
# bash Le livre de recettes : valider_avec_case
case $entree_brute in
*.societe.fr
;;
*.jpg
;;
*.[jJ][pP][gG]
;;
toto | titi
;;
[0-9][0-9][0-9]
;;
[a-z][a-z][a-z][a-z]
;;
*
;;
esac

) # Probablement un nom d'hte local.


) # Probablement un fichier JPEG.
) # Probablement un fichier JPEG, insensible
# la casse.
) # Saisie de 'toto' ou de 'titi'.
) # Un nombre 3 chiffres.
) # Un mot de 4 caractres en minuscules.
) # Autre chose.

Lorsque la correspondance de motifs nest pas suffisamment prcise et que bash est
dune version suprieure ou gale 3.0, utilisez une expression rgulire (voir la recette

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.12. Valider lentre

309

6.8, page 127). Lexemple suivant recherche un nom de fichier sur trois six caractres
alphanumriques et lextension .jpg (insensible la casse) :
[[ "$entree_brute" =~ [[:alpha:]]{3,6}\.jpg ]] && echo "Un fichier JPEG."

Discussion
Les versions rcentes de bash proposent un exemple plus complet et plus dtaill, dans
examples/scripts/shprompt. Il a t crit par Chet Ramey, le responsable de bash :
#
#
#
#
#
#
#
#
#
#
#
#

shprompt -- give a prompt and get an answer satisfying certain criteria


shprompt [-dDfFsy] prompt
s = prompt for string
f = prompt for filename
F = prompt for full pathname to a file or directory
d = prompt for a directory name
D = prompt for a full pathname to a directory
y = prompt for y or n answer
Chet Ramey
chet@ins.CWRU.Edu

Un exemple similaire se trouve dans examples/scripts.noah/y_or_n_p.bash, crit en 1993


par Noah Friedman, puis converti bash version 2 par Chet Ramey. Vous pouvez galement examiner les exemples ./functions/isnum.bash, ./functions/isnum2 et ./functions/
isvalidip.

Voir aussi

la recette 3.5, Lire lentre de lutilisateur, page 64 ;

la recette 3.6, Attendre une rponse Oui ou Non, page 65 ;

la recette 3.7, Choisir dans une liste doptions, page 68 ;

la recette 3.8, Demander un mot de passe, page 69 ;

la recette 6.6, Tester lgalit, page 124 ;

la recette 6.7, Tester avec des correspondances de motifs, page 126 ;

la recette 6.8, Tester avec des expressions rgulires, page 127 ;

la recette 6.14, Raliser des branchements multiples, page 137 ;

la recette 6.15, Analyser les arguments de la ligne de commande, page 139 ;

la recette 11.2, Fournir une date par dfaut, page 225 ;

la recette 13.6, Analyser du texte avec read, page 266 ;

la recette 13.7, Analyser avec read dans un tableau, page 267 ;

lannexe B, Exemples fournis avec bash, page 559, pour les exemples de bash.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

310

Chapitre 14 Scripts scuriss

14.13. Fixer les autorisations


Problme
Vous souhaitez fixer des autorisations de manire scurise.

Solution
Si, pour des raisons de scurit, vous devez dfinir des autorisations prcises (ou, si vous
tes certain que les permissions en place nont pas dimportance, vous pouvez juste les
changer), utilisez chmod avec un mode octal sur 4 chiffres :
$ chmod 0755 un_script

Si vous souhaitez uniquement ajouter ou retirer certaines autorisations, tout en conservant les autres, utilisez les oprations + et - en mode symbolique :
$ chmod +x un_script

vitez de fixer rcursivement les autorisations sur tous les fichiers dune structure arborescente avec une commande comme chmod -R 0644 un_rpertoire car les sous-rpertoires deviennent alors non excutables. Autrement dit, vous naurez plus accs leur
contenu, vous ne pourrez plus invoquer cd sur eux, ni aller dans leurs sous-rpertoires.
la place, utilisez find et xargs avec chmod pour fixer les autorisations des fichiers et des
rpertoires individuellement :
$ find un_rpertoire -type f | xargs chmod 0644 # Autorisations de fichier.
$ find un_rpertoire -type d | xargs chmod 0755 # Autorisations de rp.

Bien entendu, si vous voulez simplement dfinir les autorisations des fichiers dun seul
rpertoire (sans ses sous-rpertoires), allez simplement dans ce rpertoire et fixez-les.
Lorsque vous crez un rpertoire, employez une commande mkdir -m mode
nouveau_rpertoire. Ainsi, non seulement vous accomplissez deux tches en une commande, mais vous vitez toute concurrence critique entre la cration du rpertoire et la
dfinition des autorisations.

Discussion
De nombreux utilisateurs ont lhabitude demployer un mode octal sur trois chiffres.
Nous prfrons prciser les quatre chiffres possibles afin dtre parfaitement explicites.
Nous prfrons galement le mode octal car il indique clairement les autorisations rsultantes. Vous pouvez employer loprateur absolu (=) en mode symbolique, mais nous
sommes des traditionalistes qui ne veulent pas autre chose que la mthode octale.
Lorsque vous utilisez le mode symbolique avec + ou -, il est plus difficile de dterminer
les autorisations finales car ces oprations sont relatives et non absolues. Malheureusement, il existe de nombreux cas dans lesquels le remplacement des autorisations existantes ne peut se faire laide du mode octal. Vous navez alors pas dautre choix que
demployer le mode symbolique, le plus souvent avec + pour ajouter une permission
sans perturber celles dj prsentes. Pour plus de dtails, consultez la documentation de
la commande chmod propre votre systme et vrifiez que les rsultats obtenus sont
ceux attendus.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.14. Afficher les mots de passe dans la liste des processus

311

$ ls -l
-rw-r--r-- 1 jp jp 0 2005-11-06 01:44 script.sh
# Rendre le fichier lisible, modifiable et excutable pour son
# propritaire, en utilisant le mode octal.
$ chmod 0700 script.sh
$ ls -l
-rwx------ 1 jp jp 0 2005-11-06 01:44 script.sh
# Rendre le fichier lisible et excutable pour tout le monde,
# en utilisant le mode symbolique.
$ chmod ugo+rx *.sh
$ ls -l
-rwxr-xr-x 1 jp jp 0 2005-11-06 01:45 script.sh

Dans le dernier exemple, vous remarquerez que, mme si nous avons ajout (+) rx
tout le monde (ugo), le propritaire conserve son autorisation dcriture (w). Cest bien
ce que nous voulions. Mais, vous pouvez sans peine imaginer combien il peut tre facile
de faire une erreur et de donner une autorisation non voulue. Cest la raison pour laquelle nous prfrons employer le mode octal, si possible, et que nous vrifions toujours les rsultats de notre commande.
Dans tous les cas, avant dajuster les autorisations dun grand nombre de fichiers, testez
scrupuleusement votre commande. Vous pouvez galement enregistrer les autorisations et les propritaires de fichiers (voir la recette 17.8, page 439).

Voir aussi

man chmod ;

man find ;

man xargs ;

la recette 17.8, Capturer les mta-informations des fichiers pour une restauration, page
439.

14.14. Afficher les mots de passe dans la liste


des processus
Problme
ps peut afficher les mots de passe indiqus en clair sur la ligne de commande. Par exemple :
$ ./app_stupide -u utilisateur -p motdepasse &
[1] 13301

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

312
$ ps
PID
5280
9784
13301

Chapitre 14 Scripts scuriss

TT
p0
p0
p0

STAT
TIME COMMAND
S
0:00.08 -bash
R+ 0:00.00 ps
S
0:00.01 /bin/sh ./app_stupide -u utilisateur -p motdepasse

Solution
vitez de prciser les mots de passe sur la ligne de commande.

Discussion
Ce nest pas une plaisanterie, nindiquez jamais les mots de passe sur la ligne de commande.
De nombreuses applications disposent dune option -p, ou similaire, qui vous invite
saisir un mot de passe lorsquil nest pas indiqu sur la ligne de commande. Si cette approche est satisfaisante pour une utilisation interactive, ce nest pas le cas dans les scripts.
Vous pourriez tre tent dcrire un script enveloppe simple ou un alias pour encapsuler le mot de passe sur la ligne de commande. Malheureusement, cela ne fonctionne
pas car la commande est excute et apparat donc dans la liste des processus. Si la commande peut accepter le mot de passe sur STDIN, vous pouvez le passer de cette manire.
Cette approche cre dautres problmes, mais vite au moins laffichage du mot de passe
dans la liste des processus.
$ ./app_incorrecte ~.masque/motdepasse_apps_incorrectes

Si cela ne fonctionne pas, vous devrez trouver une autre application, corriger celle que
vous utilisez ou faire avec.

Voir aussi

la recette 3.8, Demander un mot de passe, page 69 ;

la recette 14.20, Utiliser des mots de passe dans un script, page 319.

14.15. crire des scripts setuid ou setgid


Problme
Vous rencontrez un problme que vous pensez pouvoir rsoudre en fixant le bit setuid
ou setgid du script shell.

Solution
Utilisez les autorisations de groupes et de fichiers dUnix et/ou sudo pour accorder aux
utilisateurs les privilges minimums dont ils ont besoin pour accomplir leur travail.
Lemploi des bits setuid et setgid sur un script shell cre plus de problmes, en particulier
de scurit, quil nen rsout. Par ailleurs, certains systmes, comme Linux, ne respec-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.15. crire des scripts setuid ou setgid

313

tent pas le bit setuid sur les scripts shell et la cration de scripts setuid ajoute des problmes de portabilit, en plus des risques de scurit.

Discussion
Les scripts setuid root sont particulirement dangereux et doivent tre totalement proscrits. la place, utilisez sudo.
setuid et setgid ont des significations diffrentes lorsquils sont appliqus des rpertoires
ou des fichiers excutables. Pour un rpertoire, lorsque lun de ces bits est positionn,
les nouveaux fichiers ou sous-rpertoires crs appartiennent, respectivement, au propritaire ou au groupe du rpertoire.
Pour vrifier si le bit setuid est positionn sur un fichier, excutez la commande test -u
(pour setgid, invoquez test -g).
$ mkdir rep_suid rep_sgid
$ touch fichier_suid fichier_sgid
$ ls -l
total 8
-rw-r--r--rw-r--r-drwxr-xr-x
drwxr-xr-x

1
1
2
2

jp
jp
jp
jp

jp
0 2007-07-31
jp
0 2007-07-31
jp 4096 2007-07-31
jp 4096 2007-07-31

21:34
21:34
21:34
21:34

fichier_sgid
fichier_suid
rep_sgid
rep_suid

21:34
21:34
21:34
21:34

fichier_sgid
fichier_suid
rep_sgid
rep_suid

$ chmod 4755 rep_suid fichier_suid


$ chmod 2755 rep_sgid fichier_sgid
$ ls -l
total 8
-rwxr-sr-x
-rwsr-xr-x
drwxr-sr-x
drwsr-xr-x

1
1
2
2

jp
jp
jp
jp

jp
0 2007-07-31
jp
0 2007-07-31
jp 4096 2007-07-31
jp 4096 2007-07-31

$ [ -u rep_suid ] && echo 'Oui, suid' || echo 'Non, pas suid'


Oui, suid
$ [ -u rep_sgid ] && echo 'Oui, suid' || echo 'Non, pas suid'
Non, pas suid
$ [ -g fichier_sgid ] && echo 'Oui, sgid' || echo 'Non, pas sgid'
Oui, sgid
$ [ -g fichier_suid ] && echo 'Oui, sgid' || echo 'Non, pas sgid'
Non, pas sgid

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

314

Chapitre 14 Scripts scuriss

Voir aussi

man chmod ;

la recette 14.18, Excuter un script sans avoir les privilges de root, page 317 ;

la recette 14.19, Utiliser sudo de manire plus sre, page 318 ;

la recette 14.20, Utiliser des mots de passe dans un script, page 319 ;

la recette 17.15, Utiliser sudo avec un groupe de commandes, page 454.

14.16. Restreindre les utilisateurs invits


La description du shell restreint donne dans cette recette apparat galement dans le
livre Le shell bash, 3e dition de Cameron Newman et Bill Rosenblatt (ditions OReilly).

Problme
Vous souhaitez accepter des utilisateurs invits sur votre systme et restreindre leurs
possibilits daction.

Solution
Si possible, vitez les comptes partags car vous perdez alors la comptabilit et crez des
problmes logistiques lorsque les utilisateurs partent (vous devez changer le mot de passe et en informer les autres utilisateurs). Crez des comptes spars avec des autorisations aussi rduites que possible, juste suffisantes pour que les utilisateurs puissent
effectuer leur travail. Vous pouvez envisager les solutions suivantes :

utiliser un environnement chroot, comme lexplique la recette 14.17, page 316 ;

passer par SSH pour autoriser des accs non interactifs aux commandes ou aux ressources, comme le dcrit la recette 14.21, page 321 ;

offrir un shell bash restreint.

Discussion
Le shell restreint est conu pour placer lutilisateur dans un environnement o ses possibilits de mouvement et dcriture de fichiers sont trs limites. Il est gnralement
employ avec les comptes d invits . Vous pouvez restreindre le shell douverture de
session dun utilisateur en plaant rbash sur sa ligne dans le fichier /etc/passwd, si cette
option a t incluse lors de la compilation du shell.
Les contraintes spcifiques imposes par le shell restreint interdit lutilisateur deffectuer les actions suivantes :

changer de rpertoire de travail : cd est inoprante. Sil tente de lemployer, il


obtient le message derreur de bash cd: restricted ;

rediriger la sortie vers un fichier : les oprateurs de redirection >, >|, <> et >> sont
interdits ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.16. Restreindre les utilisateurs invits

315

attribuer de nouvelles valeurs aux variables denvironnement $ENV, $BASH_ENV,


$SHELL et $PATH ;

invoquer des commandes contenant des barres obliques (/). Le shell considrera
que les fichiers qui se trouvent en dehors du rpertoire courant nexistent pas ;

utiliser la commande interne exec ;

prciser un nom de fichier qui contient un / en argument la commande . (source)


interne ;

importer des dfinitions de fonctions depuis lenvironnement du shell au dmarrage ;

ajouter ou supprimer des commandes internes avec les options -f et -d de la commande enable ;

spcifier loption -p la commande interne command ;

dsactiver le mode restreint avec set +r.

Ces restrictions prennent effet aprs la lecture des fichiers .bash_profile et denvironnement de lutilisateur. De plus, il est sage de fixer le propritaire des fichiers .bash_profile
et .bashrc de lutilisateur root et de les mettre en lecture seule. Les rpertoires personnels des utilisateurs doivent galement tre mis en lecture seule.
Cela signifie que lenvironnement complet de lutilisateur du shell restreint est configur dans /etc/profile et .bash_profile. Puisque lutilisateur ne peut accder /etc/profile et ne
peut modifier .bash_profile, cest ladministrateur systme qui configure lenvironnement comme il le souhaite.
Les deux manires classiques de mettre en place de tels environnements consistent
crer un rpertoire des commandes sres et de ne mettre que celui-ci dans PATH, et de
configurer un menu de commandes depuis lequel lutilisateur ne peut sortir sans quitter le shell.
Le shell restreint ne rsistera pas un assaillant dtermin. Il sera galement peut-tre difficile verrouiller autant que vous le voudriez car
de nombreuses applications classiques, comme vi et Emacs, autorisent
des chappements vers le shell, qui peuvent passer outre le shell restreint.
Utilis de manire adquate, il ajoute un niveau de scurit apprciable, mais il ne doit pas reprsenter la seule scurit.

Le shell Bourne doriginal dispose galement dune version restreinte, appele rsh, qui
peut tre confondue avec les outils (rsh, rcp, rlogin, etc.) du Remote Shell (rsh). Le Remote Shell ne nest pas vraiment sr et a t remplac par SSH (le Secure Shell).

Voir aussi

la recette 14.17, Utiliser un environnement chroot, page 316 ;

la recette 14.21, Utiliser SSH sans mot de passe, page 321.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

316

Chapitre 14 Scripts scuriss

14.17. Utiliser un environnement chroot


Problme
Vous devez employer un script ou une application qui nest pas digne de confiance.

Solution
Placez le script ou lapplication dans un environnement chroot. La commande chroot
change le rpertoire racine du processus en cours en lui attribuant le rpertoire que
vous indiquez, puis retourne un shell ou excute la commande prcise. Ainsi, le processus, et donc le programme, est plac dans une prison de laquelle il ne peut, en
thorie, schapper et aller vers le rpertoire parent. Par consquent, si lapplication est
compromise ou effectue des oprations malveillantes, elle ne peut affecter que la petite
partie du systme de fichiers dans laquelle vous lavez confine. Associe un utilisateur
aux droits trs limits, cette approche ajoute un niveau de scurit intressant.
Malheureusement, la description complte de chroot sort du cadre de cette recette, puisque cette commande pourrait faire lobjet dun livre elle seule. Nous la prsentons ici
pour que vous en apprciiez les fonctionnalits.

Discussion
Pourquoi ne peut-on pas tout excuter dans des environnements chroot ? Tout simplement parce que de nombreuses applications ont besoin dinteragir avec dautres applications, des fichiers, des rpertoires ou des sockets qui se trouvent sur le systme de
fichiers global. Il sagit du point dlicat des environnements chroot ; lapplication na pas
accs ce qui se trouve hors des murs de sa prison et tout ce dont elle a besoin doit donc
sy trouver. Plus lapplication est complexe, plus il est difficile de lexcuter dans un environnement chroot.
Les applications qui doivent tre accessibles depuis lInternet, comme les serveurs DNS
(par exemple, BIND), web et de messagerie (par exemple, Postfix), peuvent tre configures, avec plus ou moins de difficults, pour fonctionner dans un environnement
chroot. Pour plus de dtails, consultez la documentation de votre distribution et des applications concernes.
chroot est galement utile lors de la reprise dun systme. Aprs avoir dmarr partir
dun Live CD et mont le systme de fichier racine sur votre disque dur, vous pourriez
avoir excuter un outil, comme Lilo ou Grub, qui, selon votre configuration, devra
peut-tre croire quil sexcute rellement sur le systme endommag. Si le Live CD et
le systme install ne sont pas trop diffrents, vous pouvez gnralement invoquer
chroot sur le point de montage du systme endommag et le rparer. Cela fonctionne
car tous les outils, bibliothques, fichiers de configuration et priphriques existent dj
dans lenvironnement chroot. En effet, il sagit en ralit dun systme complet, mme
sil ne fonctionne pas (encore). Vous devrez peut-tre ajuster votre $PATH pour trouver
ce dont vous avez besoin aprs avoir invoqu chroot (cest lun des aspects de si le Live
CD et le systme install ne sont pas trop diffrents ).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.18. Excuter un script sans avoir les privilges de root

317

Vous pourriez galement tre intress par les contrles daccs obligatoires (MAC
Mandatory Access Controls) de SELinux (Security Enhanced Linux) de la NSA. MAC permet
de cibler trs prcisment au niveau systme ce qui est autoris ou non et les interactions entre les diffrents composants du systme. Une dfinition est appele politique de
scurit et ses effets sont trs similaires un environnement chroot, car une application
ou un processus ne peut effectuer que ce que la politique lui permet.
Red Hat Linux inclut SELinux dans sa version entreprise. SUSE de Novell dispose dune
implmentation MAC similaire appele AppArmor. Il existe des implmentations quivalentes pour Solaris, BSD et MacOS X.

Voir aussi

man chroot ;

http://www.nsa.gov/selinux/ ;

http://fr.wikipedia.org/wiki/Mandatory_access_control ;

http://olivier.sessink.nl/jailkit/ ;

http://www.jmcresearch.com/projects/jail/.

14.18. Excuter un script sans avoir les


privilges de root
Problme
Vous souhaitez excuter vos scripts en tant quutilisateur autre que root, mais vous craignez ne pas tre autoris effectuer les tches ncessaires.

Solution
Excutez vos scripts avec des identifiants dutilisateurs autres que root, cest--dire sous
votre compte ou ceux dutilisateurs rservs, et nemployez pas le shell en mode interactif avec le compte root, mais configurez sudo de manire effectuer les tches qui requirent des privilges plus levs.

Discussion
sudo peut tre utilis dans un script aussi facilement que depuis la ligne de commande
du shell. En particulier, voyez loption NOPASSWD de sudoers et la recette 14.19, page 318.

Voir aussi

man sudo ;

man sudoers ;

la recette 14.15, crire des scripts setuid ou setgid, page 312 ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

318

Chapitre 14 Scripts scuriss

la recette 14.19, Utiliser sudo de manire plus sre, page 318 ;

la recette 14.20, Utiliser des mots de passe dans un script, page 319 ;

la recette 17.15, Utiliser sudo avec un groupe de commandes, page 454.

14.19. Utiliser sudo de manire plus sre


Problme
Vous souhaitez utiliser sudo mais ne voulez pas accorder des privilges trop levs tout
le monde.

Solution
Cest trs bien ! Vous vous proccupez de la scurit. Mme si lutilisation de sudo augmente la scurit, sa configuration par dfaut peut tre amliore.
Prenez le temps dapprendre employer sudo et le fichier /etc/sudoers. En particulier,
vous devez savoir que, dans la plupart des cas, la configuration ALL=(ALL) ALL est
inutile ! Bien entendu, elle fonctionnera, mais elle nest pas trs sre. Cela quivaut
donner le mot de passe de root tous les utilisateurs, mais sans quils le sachent. Ils disposent des mmes possibilits daction que root. sudo journalise les commandes excutes, mais il est facile de passer outre ces traces en invoquant sudo bash.
Vous devez galement bien rf lchir vos besoins. Tout comme vous devez viter la
configuration ALL=(ALL) ALL, vous devez viter de grer les utilisateurs un par un. Le
fichier sudoers permet dobtenir une gestion trs fine et nous vous conseillons fortement
de lutiliser. man sudoers affiche une documentation complte et plusieurs exemples, en
particulier dans la section expliquant comment empcher les chappements vers le
shell.
sudoers accepte quatre types dalias : utilisateur (user), personne pour laquelle on se fait
passer (runas), machine (host) et commande (command). Une utilisation judicieuse de
ces alias en tant que rles ou groupes permet de rduire la maintenance. Par exemple,
vous pouvez dfinir un User_Alias pour UTILISATEURS_COMPILATION, puis, avec
Host_Alias, indiquer les machines que ces utilisateurs doivent employer et, avec
Cmnd_Alias, prciser les commandes quils doivent invoquer. Si votre stratgie consiste
modifier /etc/sudoers sur une machine et le recopier priodiquement sur les autres
systmes concerns en utilisant scp avec une authentification cl publique, vous pouvez mettre en place un systme trs scuris qui accorde uniquement les privilges ncessaires.
Lorsque sudo vous demande un mot de passe, il sagit du vtre. Cest-dire celui de votre compte dutilisateur et non de celui de root. Il est
assez frquent de commencer pas saisir celui de root.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.20. Utiliser des mots de passe dans un script

319

Discussion
Malheureusement, sudo nest pas install par dfaut sur tous les systmes. Il lest gnralement sur Linux et OpenBSD ; pour les autres systmes, cela varie. Consultez la documentation de votre systme et installez sudo sil nest pas dj prsent.
Vous devez toujours modifier le fichier /etc/sudoers laide de visudo.
Comme vipw, visudo verrouille le fichier afin quune seule personne
la fois puisse lditer et il effectue certains contrles de syntaxe avant de
remplacer le fichier officiel. Ainsi, vous ne bloquerez pas par mgarde
votre propre systme.

Voir aussi

man sudo ;

man sudoers ;

man visudo ;

SSH, le shell scuris La rfrence de Daniel J. Barrett (ditions OReilly) ;

la recette 14.15, crire des scripts setuid ou setgid, page 312 ;

la recette 14.18, Excuter un script sans avoir les privilges de root, page 317 ;

la recette 14.20, Utiliser des mots de passe dans un script, page 319 ;

la recette 17.15, Utiliser sudo avec un groupe de commandes, page 454.

14.20. Utiliser des mots de passe dans un script


Problme
Vous devez indiquer explicitement un mot de passe dans un script.

Solution
Il sagit videmment dune mauvaise ide, qui doit tre proscrite. Malheureusement, il
nexiste parfois aucune autre solution.
Tout dabord, vous devez vrifier si vous ne pouvez pas utiliser sudo avec loption NOPASSWD pour viter dindiquer explicitement un mot de passe. Cette approche a galement des inconvnients, mais vous devez lessayer. Pour plus dinformations, consultez
la recette 14.19, page 318.
Une autre solution sappuie sur SSH avec des cls publiques et des commandes restreintes (voir la recette 14.21, page 321).
Si ces deux solutions ne vous conviennent pas, placez lidentifiant et le mot de passe de
lutilisateur dans un fichier spar, uniquement lisible par lutilisateur qui en a besoin.
Ensuite, chargez ce fichier au moment opportun (voir la recette 10.3, page 210). Bien entendu, laissez ce fichier en dehors de tout systme de gestion des versions.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

320

Chapitre 14 Scripts scuriss

Discussion
Grce SSH (voir les recettes 14.21, page 321, et 15.11, page 354), il est relativement facile daccder de manire scurise des donnes distantes. Il est mme possible demployer SSH pour accder des donnes sur lhte local, mais il est alors probablement
plus efficace dutiliser sudo. Mais comment accder des donnes enregistres dans une
base de donnes distante, peut-tre via une commande SQL ? Dans ce cas, il ny a pas
grand-chose faire.
Et pourquoi ne pas se servir de crypt ou dautres outils de chiffrement des mots de
passe ? Le problme vient des mthodes scurises denregistrement des mots de passe
qui impliquent toute lutilisation dune fonction de hachage sens unique. Autrement
dit, il est thoriquement impossible de retrouver, partir du code de hachage, le mot
de passe en clair. Cest l que le bt blesse. Nous avons besoin du mot de passe en clair
pour accder la base de donnes ou un autre serveur. Le stockage scuris nest donc
pas une option.
Il ne reste donc plus que le stockage non scuris, mais cette approche peut tre pire
quun mot de passe en clair car elle apporte un faux sentiment de scurit. Cependant,
si elle vous convient, et si vous promettez de faire attention, utilisez-la et masquez le
mot de passe avec une mthode de chiffrement de type ROT13 ou autre. Puisque ROT13
naccepte que les lettres ASCII, vous pouvez opter pour ROT47 afin de prendre en charge les symboles de ponctuation.
$ ROT13=$(echo password | tr 'A-Za-z' 'N-ZA-Mn-za-m')
$ ROT47=$(echo password | tr '!-~' 'P-~!-O')
Nous souhaitons insister sur le fait que ROT13 ou ROT47 ne constitue
rien dautre quune scurit par lobscurit et donc aucune scurit
relle. Cette approche vaut mieux que rien si, et uniquement si, vous
nimaginez pas que vous tes en scurit alors que ce nest pas le cas.
Vous devez simplement avoir conscience des risques. Cela dit, les avantages contrebalancent parfois les risques.

Voir aussi

http://fr.wikipedia.org/wiki/ROT13 ;

la recette 10.3, Utiliser des fichiers de configuration dans un script, page 210 ;

la recette 14.15, crire des scripts setuid ou setgid, page 312 ;

la recette 14.18, Excuter un script sans avoir les privilges de root, page 317 ;

la recette 14.19, Utiliser sudo de manire plus sre, page 318 ;

la recette 14.21, Utiliser SSH sans mot de passe, page 321 ;

la recette 15.11, Obtenir lentre depuis une autre machine, page 354 ;

la recette 17.15, Utiliser sudo avec un groupe de commandes, page 454.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.21. Utiliser SSH sans mot de passe

321

14.21. Utiliser SSH sans mot de passe


Problme
Vous devez employer SSH ou scp dans un script, mais ne souhaitez pas utiliser un mot
de passe, ou bien, ils doivent servir dans une tche cron et ne peuvent donc avoir un mot
de passe1.
SSH1 (le protocole) et SSH1 (lexcutable) sont devenus obsoltes et
sont considrs moins srs que le nouveau protocole SSH2 et son
implmentation par OpenSSH et SSH Communications Security. Nous
vous conseillons fortement demployer SSH2 avec OpenSSH. Nous ne
prsenterons pas SSH1.

Solution
Il existe deux manires dutiliser SSH sans mot de passe, la bonne et la mauvaise. La
mauvaise consiste employer une cl publique non chiffre par une phrase de passe. La
bonne repose sur lutilisation avec ssh-agent ou keychain dune cl publique protge par
une phrase de passe.
Nous supposons que vous vous servez dOpenSSH ; si ce nest pas le cas, consultez votre
documentation (les commandes et les fichiers seront similaires).
Tout dabord, vous devez crer une paire de cls, si vous nen possdez pas dj une. Une
seule paire de cls est ncessaire pour vous authentifier auprs de toutes les machines
que vous configurez, mais vous pouvez choisir dutiliser plusieurs paires, peut-tre pour
des utilisations personnelles et professionnelles. La paire est constitue dune cl prive,
que vous devez protger tout prix, et dune cl publique (*.pub), que vous pouvez diffuser. Les deux sont lies par une fonction mathmatique complexe, qui leur permet de
sidentifier lune et lautre, mais qui ne permet pas de dduire lune de lautre.
Utilisez ssh-keygen (peut-tre ssh-keygen2 si vous ne vous servez pas dOpenSSH) pour
crer une paire de cls. Loption -t est obligatoire et ses arguments sont rsa ou dsa. -b
est facultative et prcise le nombre de bits de la nouvelle cl (1024 par dfaut, au moment de lcriture de ces lignes). -C permet dajouter un commentaire, qui vaut par dfaut utilisateur@nom_de_machine. Nous vous conseillons les paramtres -t dsa -b 2048
et vous recommandons fortement dutiliser une phrase de passe. ssh-keygen vous permet
galement de modifier la phrase de passe et le commentaire du fichier de cl.
$ ssh-keygen
You must specify a key type (-t).
Usage: ssh-keygen [options]

1. Nous remercions Richard Silverman et Daniel Barrett pour leurs ides et leurs excellentes
explications dans les livres SSH, le shell scuris La rfrence (ditons OReilly), en particulier
les chapitres 2, 6 et 11, et Linux Security Cookbook (OReilly Media), qui ont normment profit
cette recette.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

322
Options:
-b bits
-c
-e
-f filename
-g
-i
-l
-p
-q
-y
-t type
-B
-H
-F hostname
-C comment
-N phrase
-P phrase
-r hostname
-G file
-T file

Chapitre 14 Scripts scuriss

Number of bits in the key to create.


Change comment in private and public key files.
Convert OpenSSH to IETF SECSH key file.
Filename of the key file.
Use generic DNS resource record format.
Convert IETF SECSH to OpenSSH key file.
Show fingerprint of key file.
Change passphrase of private key file.
Quiet.
Read private key file and print public key.
Specify type of key to create.
Show bubblebabble digest of key file.
Hash names in known_hosts file
Find hostname in known hosts file
Provide new comment.
Provide new passphrase.
Provide old passphrase.
Print DNS resource record.
Generate candidates for DH-GEX moduli
Screen candidates for DH-GEX moduli

$ ssh-keygen -t dsa -b 2048 -C 'Voici ma nouvelle cle'


Generating public/private dsa key pair.
Enter file in which to save the key (/home/jp/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/jp/.ssh/id_dsa.
Your public key has been saved in /home/jp/.ssh/id_dsa.pub.
The key fingerprint is:
84:6f:45:fc:08:3b:ce:b2:4f:2e:f3:5e:b6:9f:65:63 Voici ma nouvelle cle
$ ls -l id_dsa*
-rw------- 1 jp
-rw-r--r-- 1 jp

jp 1264 Dec 13 23:39 id_dsa


jp 1120 Dec 13 23:39 id_dsa.pub

$ cat id_dsa.pub
ssh-dss
AAAAB3NzaC1kc3MAAAEBANpgvvTslst2m0ZJA0ayhh1Mqa3aWwU3kfv0m9+myFZ9veFsxM7IVxI
jWfAlQh3jplY+Q78fMzCTiG+ZrGZYn8adZ9yg5/wAC03KXm2vKt8LfTx6I+qkMR7v15NI7tZyhx
Gah5qHNehReFWLuk7JXCtRrzRvWMdsHc/L2SA1Y4fJ9Y9FfVlBdE1Er+ZIuc5xIlO6D1HFjKjt3
wjbAal+oJxwZJaupZ0Q7N47uwMslmc5ELQBRNDsaoqFRKlerZASPQ5P+AH/+Cxa/fCGYwsogXSJ
J0H5S7+QJJHFze35YZI/+A1D3BIa4JBf1KvtoaFr5bMdhVAkChdAdMjo96xhbdEAAAAVAJSKzCE
srUo3KAvyUO8KVD6e0B/NAAAA/3u/Ax2TIB/M9MmPqjeH67Mh5Y5NaVWuMqwebDIXuvKQQDMUU4
EPjRGmS89Hl8UKAN0Cq/C1T+OGzn4zrbE06CO/Sm3SRMP24HyIbElhlWV49sfLR05Qmh9fRl1s7
ZdcUrxkDkr2J6on5cMVB9M2nIl90IhRVLd5RxP01u81yqvhvE61ORdA6IMjzXcQ8ebuD2R733O3
7oGFD7e2O7DaabKKkHZIduL/zFbQkzMDK6uAMP8ylRJN0fUsqIhHhtc//16OT2H6nMU09MccxZT
FUfqF8xIOndElP6um4jXYk5Q30i/CtU3TZyvNeWVwyGwDi4wg2jeVe0YHU2Rh/ZcZpwAAAQEAv2
O86701U9sIuRijp8sO4h13eZrsE5rdn6aul/mkm+xAlO+WQeDXR/ONm9BwVSrNEmIJB74tEJL3q
QTMEFoCoN9Kp00Ya7Qt8n4gZ0vcZlI5u+cgyd1mKaggS2SnoorsRlb2Lh/Hpe6mXus8pUTf5QT8

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.21. Utiliser SSH sans mot de passe

323

apgXM3TgFsLDT+3rCt40IdGCZLaP+UDBuNUSKfFwCru6uGoXEwxaL08Nv1wZOc19qrc0Yzp7i33
m6i3a0Z9Pu+TPHqYC74QmBbWq8U9DAo+7yhRIhq/fdJzk3vIKSLbCxg4PbMwx2Qfh4dLk+L7wOa
sKnl5//W+RWBUrOlaZ1ZP1/azsK0Ncygno/0F1ew== Voici ma nouvelle cle

Lorsque vous disposez dune paire de cls, ajoutez la cl publique au fichier


~/.ssh/authorized_keys dans votre rpertoire personnel sur les autres machines auxquelles
vous souhaitez vous connecter laide de cette paire. Pour cela, vous pouvez vous servir
de scp, de cp avec une disquette ou une cl USB, ou simplement la copier et la coller entre des sessions de terminal. Il faut juste quelle se trouve sur une mme ligne. Bien que
vous puissiez employer une seule commande (par exemple, scp id_dsa.pub
hote_distant:.ssh/authorized_keys), nous dconseillons cette solution, mme si
vous tes absolument certain que le fichier authorized_keys nexiste pas. Nous prconisons une commande, certe plus complexe, mais beaucoup plus fiable :
$ ssh hote_distant "echo $(cat ~/.ssh/id_dsa.pub) >> ~/.ssh/authorized_keys"
jp@hote_distant's password:
$ ssh hote_distant
Last login: Thu Dec 14 00:02:52 2006 from openbsd.jpsdomai
NetBSD 2.0.2 (GENERIC) #0: Wed Mar 23 08:53:42 UTC 2005
Welcome to NetBSD!
-bash-3.00$ exit
logout
Connection to hote_distant closed.

Comme vous pouvez le constater, nous devons entrer un mot de passe lors de la copie
initiale, mais, ensuite, ssh ne le demande plus. En ralit, nous venons dillustrer lutilisation de ssh-agent, qui a rcupr la phrase de passe de la cl afin que nous nayons pas
la saisir.
La commande prcdente suppose galement que le rpertoire ~/.ssh existe sur les deux
machines. Si ce nest pas le cas, crez-le par mkdir -m 0700 -p ~/.ssh. Pour quOpenSSH
fonctionne, le rpertoire ~/.ssh doit possder les autorisations 0700. Il est galement prfrable de donner les autorisations 0600 ~/.ssh/authorized_keys.
Vous noterez que la relation cre est sens unique. Nous pouvons utiliser SSH depuis
lhte local vers lhte distant sans mot de passe, mais linverse nest pas vrai car il manque la cl prive et lagent sur lhte distant. Vous pouvez simplement copier votre cl
prive sur toutes les machines afin de crer un rseau SSH sans mot de passe, mais le
changement de la phrase de passe est alors plus complexe et il est plus difficile de scuriser la cl prive. Si possible, il est prfrable de disposer dune machine bien protge
et fiable partir de laquelle vous vous connectez aux htes distants avec ssh.
Lagent SSH est intelligent et son utilisation subtile. Nous pourrions mme dire trop intelligent. Son utilisation prvue passe par eval et une substitution de commande : eval
`ssh-agent`. Deux variables denvironnement sont alors cres. ssh ou scp les utilisent
pour trouver lagent et lui demander les informations didentit. Cette solution est trs
habile et trs bien documente. Le seul problme est que cette approche est diffrente
des autres programmes couramment employs ( lexception de certaines fonctionnalits de less, voir la recette 8.15, page 189) et totalement incomprhensible aux utilisateurs
nophytes ou mal informs.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

324

Chapitre 14 Scripts scuriss

Si vous excutez uniquement lagent, il affiche quelques informations et semble fonctionner. Cest effectivement le cas, car il est bien en cours dexcution. Cependant, il neffectue aucune opration, puisque les variables denvironnement ncessaires nont pas
t dfinies. Mentionnons galement loption -k qui demande lagent de se terminer.
# La mauvaise manire dutiliser lagent.
# Aucune variable denvironnement adquate.
$ set | grep SSH
$
$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-bACKp27592/agent.27592; export SSH_AUTH_SOCK;
SSH_AGENT_PID=24809; export SSH_AGENT_PID;
echo Agent pid 24809;
# Toujours rien.
$ set | grep SSH
$
# Il est mme impossible de le tuer, puisque -k a besoin de $SSH_AGENT_PID.
$ ssh-agent -k
SSH_AGENT_PID not set, cannot kill agent
# Est-il
$ ps x
PID TT
24809 ??
22903 p0
11303 p0

en cours dexcution ? Oui.


STAT
Is
I
R+

TIME
0:00.01
0:03.05
0:00.00

COMMAND
ssh-agent
-bash (bash)
ps -x

$ kill 24809
$ ps x
PID TT STAT
22903 p0 I
30542 p0 R+

TIME COMMAND
0:03.06 -bash (bash)
0:00.00 ps -x

# Toujours la mauvaise manire demployer lagent.


# Cette commande est correcte.
$ eval `ssh-agent`
Agent pid 21642
# a marche !
$ set | grep SSH
SSH_AGENT_PID=21642
SSH_AUTH_SOCK=/tmp/ssh-ZfEsa28724/agent.28724
# Tuer lagent, de la mauvaise manire.
$ ssh-agent -k
unset SSH_AUTH_SOCK;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.21. Utiliser SSH sans mot de passe

325

unset SSH_AGENT_PID;
echo Agent pid 21642 killed;
# Le processus a bien disparu, mais il na pas fait le mnage.
$ set | grep SSH
SSH_AGENT_PID=21642
SSH_AUTH_SOCK=/tmp/ssh-ZfEsa28724/agent.28724

# La bonne manire dutiliser lagent.


$ eval `ssh-agent`
Agent pid 19330
$ set | grep SSH
SSH_AGENT_PID=19330
SSH_AUTH_SOCK=/tmp/ssh-fwxMfj4987/agent.4987
$ eval `ssh-agent -k`
Agent pid 19330 killed
$ set | grep SSH
$

Comme vous pouvez le constater, lemploi de lagent nest pas trs intuitif. Il est peuttre trs habile, trs efficace, trs subtil, mais en aucun cas convivial.
Une fois lagent en excution, nous devons charger les informations didentit laide
de la commande ssh-add. Cette opration est trs simple, puisquil suffit dexcuter cette
commande, avec, de manire facultative, la liste des fichiers de cls charger. Elle demande la saisie de toutes les phrases de passe ncessaires. Dans lexemple suivant, nous
nindiquons aucune cl et elle utilise simplement celle par dfaut dfinie dans le fichier
de configuration principal de SSH :
$ ssh-add
Enter passphrase for /home/jp/.ssh/id_dsa:
Identity added: /home/jp/.ssh/id_dsa (/home/jp/.ssh/id_dsa)

Nous pouvons prsent employer SSH interactivement, dans cette session du shell,
pour nous connecter toute machine configure prcdemment, sans saisir un mot ou
une phrase de passe. Mais, quen est-il des autres sessions, scripts ou tches cron ?
Pour cela, utilisez le script keychain (http://www.gentoo.org/proj/en/keychain/) de Daniel
Robbins. En effet, il :
[agit] comme une interface ssh-agent, en vous permettant de crer un processus sshagent par systme et non par session. Cette approche permet de rduire considrablement le nombre de saisies de la phrase de passe. Elle ne se fait plus chaque nouvelle
connexion, mais chaque dmarrage de la machine locale.
[...]
keychain permet galement aux tches cron dexploiter de manire propre et scurise les cls RSA/DSA, sans avoir employer des cls prives non chiffres peu sres.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

326

Chapitre 14 Scripts scuriss

keychain est un script shell bien conu, bien crit et bien document. Il automatise et
gre le processus fastidieux dexportation des variables denvironnement dcrites prcdemment dans dautres sessions. Il les rend galement disponibles aux scripts et cron.
En y rf lchissant, vous pourriez trouver un problme cette approche. En effet, toutes
les cls sont confies ce script, jusqu ce que la machine redmarre. En ralit, ce point
nest pas aussi risqu quil parat.
Premirement, vous pouvez toujours le tuer, mais les scripts et cron ne pourront plus
en bnficier. Deuximement, son option --clean permet de retirer les cls mises en
cache lorsque que vous ouvrez une session. Voici les dtails, donns par lauteur de
keychain (publis initialement par IBM developerWorks http://www.ibm.com/developerworks/, voir http://www.ibm.com/developerworks/linux/library/l-keyc2/) :
Jai expliqu prcdemment que lemploi de cls prives non chiffres est une pratique dangereuse, car elle permet quiconque de voler votre cl prive et de lutiliser
pour se connecter vos comptes distants, partir de nimporte quel systme, sans
fournir un mot de passe. Mme si keychain nest pas vulnrable ce type de problmes (tant que vous utilisez des cls prives chiffres), il prsente un point faible potentiellement exploitable directement li au fait quil facilite le dtournement du
processus ssh-agent de longue dure. Que se passe-t-il si un intrus est en mesure de
dterminer mon mot ou ma phrase de passe et se connecte mon systme local ? Sil
est capable douvrir une session sous mon nom dutilisateur, keychain lui accorde un
accs instantan mes cls prives dchiffres et donc tous mes autres comptes.
Avant de poursuivre, tudions cette menace. Si un utilisateur malveillant est en mesure douvrir une session sous mon nom, keychain lui autorise effectivement un accs mes comptes distants. Cependant, il sera trs difficile lintrus dobtenir mes
cls prives dchiffres puisquelles sont toujours chiffres sur le disque. Par ailleurs,
pour obtenir accs mes cls prives, il faut que lutilisateur ouvre une session sous
mon nom et ne lise pas simplement les fichiers dans mon rpertoire. Par consquent,
dtourner ssh-agent est une tche plus complexe que le vol dune cl prive non chiffre, pour lequel lintrus simplement besoin daccder aux fichiers de mon rpertoire ~/.ssh, quil ait ouvert une session sous mon nom ou sous un autre nom.
Nanmoins, si un assaillant est en mesure de se connecter sous mon nom, il peut causer de nombreux dommages en utilisant mes cls prives dchiffres. Par consquent,
si vous voulez employer keychain sur un serveur que vous surveillez peu, utilisez
loption --clear afin dapporter un niveau de scurit supplmentaire.
Loption --clear indique keychain que toute nouvelle connexion votre compte
doit tre considre comme une faille potentielle pour la scurit, except en cas de
preuve contraire. Lorsque keychain est dmarr avec loption --clear, il commence
par effacer, au moment de la connexion, toutes les cls prives qui se trouvent dans
le cache de ssh-agent. Par consquent, si vous tes un intrus, keychain vous demande
des phrases de passe au lieu de vous donner accs aux cls existant dans le cache. Cependant, mme si cela amliore la scurit, lutilisation est moins conviviale et trs
similaire lexcution de ssh-agent lui-mme, sans keychain. Comme cest souvent le
cas, il faut choisir entre scurit et convivialit.
Malgr tout, lutilisation de keychain avec --clear prsente des avantages par rapport
celle de ssh-agent seul. En effet, avec keychain --clear, vos tches cron et vos scripts
peuvent toujours tablir des connexions sans mot de passe, puisque les cls prives
sont effaces la connexion et non la dconnexion. La dconnexion dun systme
ne constituant pas une brche potentielle dans la scurit, il ny a aucune raison que

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.21. Utiliser SSH sans mot de passe

327

keychain y rponde par la suppression des cls de ssh-agent. Ainsi, loption --clear est
parfaitement adapte aux serveurs peu frquents qui doivent raliser occasionnellement des tches de copies scurises, comme les serveurs de sauvegarde, les pare-feu
et les routeurs.

Pour utiliser ssh-agent au travers de keychain dans un script ou avec cron, chargez simplement le fichier cr par keychain pour votre script. keychain peut galement grer les cls
GPG (GNU Privacy Guard) :
[ -r ~/.ssh-agent ] && source ~/.ssh-agent \
|| { echo "keychain nest pas dmarr" >&2 ; exit 1; }

Discussion
Lorsque vous utilisez SSH dans un script, il est assez pnible de devoir sauthentifier ou
de recevoir des avertissements. Loption -q active le mode silencieux et supprime les
avertissements, tandis que -o 'BatchMode yes' empche les invites. videmment, si
SSH ne dispose daucun moyen de sauthentifier, il choue.
SSH est un outil merveilleux et mrite un traitement plus dtaill. Nous vous conseillons fortement le livre SSH, le shell scuris La rfrence de Richard E. Silverman
et Daniel J. Barrett (ditions OReilly), pour tout ce que vous avez envie de savoir sur
SSH.
Lutilisation de cls publiques entre OpenSSH et SSH2 Server de SSH Communications
Security peut tre assez complexe. Pour plus dinformations, consultez le chapitre 6 du
livre Linux Security Cookbook de Daniel J. Barrett et autres (OReilly Media).
IBM developerWorks propose plusieurs articles sur SSH rdigs par Daniel Robbins, le
crateur de keychain et larchitecte en chef de Gentoo (http://www.ibm.com/developerworks/linux/library/l-keyc.html, http://www.ibm.com/developerworks/linux/library/l-keyc2/
et http://www.ibm.com/developerworks/linux/library/l-keyc3/).
Si keychain ne semble pas fonctionner ou sil fonctionne pendant un certain temps puis
semble sarrter, il est probable quun autre script excute lui aussi ssh-agent et perturbe
le processus. Vrifiez les informations suivantes et assurez-vous que les PID et les sockets
sont cohrents. Selon votre systme dexploitation, vous devrez modifier la commande
ps (si -ef ne fonctionne pas, essayez -eu).
$ ps -ef | grep [s]sh-agent
jp
17364 0.0 0.0 3312 1132 ?

Dec16

0:00 ssh-agent

$ cat ~/.keychain/$HOSTNAME-sh
SSH_AUTH_SOCK=/tmp/ssh-UJc17363/agent.17363; export SSH_AUTH_SOCK;
SSH_AGENT_PID=17364; export SSH_AGENT_PID;
$ set | grep SSH_A
SSH_AGENT_PID=17364
SSH_AUTH_SOCK=/tmp/ssh-UJc17363/agent.17363

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

328

Chapitre 14 Scripts scuriss

Empreintes dune cl
Toutes les versions de SSH prennent en charge les empreintes, qui facilitent la
comparaison et la vrification des cls, que ce soit celles de lutilisateur ou de lhte. Comme vous pouvez limaginer, la vrification bit par bit dune longue suite
de donnes alatoires est fastidieuse et sujette aux erreurs, voire virtuellement impossible (par exemple, par tlphone). Les empreintes permettent deffectuer cette vrification beaucoup plus facilement. Vous avez sans doute dj rencontr des
empreintes avec dautres applications, en particulier les cls PGP/GPG.
La principale raison de vrifier les cls est dempcher les attaques de type homme
du milieu. Si Alice envoie sa cl Bob, celui-ci doit sassurer que la cl reue est
rellement celle dAlice et que Eve ne la pas intercepte et envoy la sienne la
place. Pour cela, il faut un canal de communication spar, comme un tlphone.
Il existe deux formats dempreintes, le format hexadcimal classique de PGP et le
nouveau format bubblebabble, suppos plus facile lire. Lorsque Bob reoit la cl
dAlice, il lappelle et lui lit lempreinte. Si les deux correspondent, les deux intervenants savent que Bob dispose de la bonne cl.
$ ssh-keygen -l -f ~/.ssh/id_dsa
2048 84:6f:45:fc:08:3b:ce:b2:4f:2e:f3:5e:b6:9f:65:63
/home/jp/.ssh/id_dsa.pub
$ ssh-keygen -l -f ~/.ssh/id_dsa.pub
2048 84:6f:45:fc:08:3b:ce:b2:4f:2e:f3:5e:b6:9f:65:63
/home/jp/.ssh/id_dsa.pub
$ ssh-keygen -B -f ~/.ssh/id_dsa
2048 xosev-kytit-rakyk-tipos-bocuh-kotef-mupyc-hozok-zalip-pezad-nuxox
/home/jp/.ssh/id_dsa.pub
$ ssh-keygen -B -f ~/.ssh/id_dsa.pub
2048 xosev-kytit-rakyk-tipos-bocuh-kotef-mupyc-hozok-zalip-pezad-nuxox
/home/jp/.ssh/id_dsa.pub

Voir aussi

http://www.gentoo.org/proj/en/keychain/ ;

http://www.ibm.com/developerworks/linux/library/l-keyc2/ ;

SSH, le shell scuris La rfrence de Richard E. Silverman et Daniel J. Barrett (ditions OReilly) ;

Linux Security Cookbook de Daniel J. Barrett et autres (OReilly Media) ;

Cryptographie : En pratique de Niels Ferguson et Bruce Schneier (Vuibert) ;

Cryptographie applique de Bruce Schneier (Vuibert) ;

la recette 8.15, Aller plus loin avec less, page 189.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.22. Restreindre les commandes SSH

329

14.22. Restreindre les commandes SSH


Problme
Vous souhaitez limiter les possibilits dun utilisateur ou dun script SSH2.

Solution
Modifiez le fichier ~/.ssh/authorized_keys, utilisez des commandes forces SSH et, en option, dsactivez les fonctionnalits SSH inutiles. Par exemple, supposons que vous souhaitiez autoriser un processus rsync sans lutilisation interactive.
Tout dabord, vous devez dterminer prcisment la commande qui sera excute sur le
ct distant. Crez une cl (voir la recette 14.21, page 321) et ajoutez une commande force. Ouvrez le fichier ~/.ssh/authorized_keys et ajoutez la ligne suivante avant la cl :
command="/bin/echo La commande etait : $SSH_ORIGINAL_COMMAND"

Vous devez obtenir une entre similaire la suivante (sur une seule ligne) :
command="/bin/echo La commande etait : $SSH_ORIGINAL_COMMAND" ssh-dss
AAAAB3NzaC1kc3MAAAEBANpgvvTslst2m0ZJA0ayhh1Mqa3aWwU3kfv0m9+myFZ9veFsxM7IVxI
jWfAlQh3jplY+Q78fMzCTiG+ZrGZYn8adZ9yg5/wAC03KXm2vKt8LfTx6I+qkMR7v15NI7tZyhx
Gah5qHNehReFWLuk7JXCtRrzRvWMdsHc/L2SA1Y4fJ9Y9FfVlBdE1Er+ZIuc5xIlO6D1HFjKjt3
wjbAal+oJxwZJaupZ0Q7N47uwMslmc5ELQBRNDsaoqFRKlerZASPQ5P+AH/+Cxa/fCGYwsogXSJ
J0H5S7+QJJHFze35YZI/+A1D3BIa4JBf1KvtoaFr5bMdhVAkChdAdMjo96xhbdEAAAAVAJSKzCE
srUo3KAvyUO8KVD6e0B/NAAAA/3u/Ax2TIB/M9MmPqjeH67Mh5Y5NaVWuMqwebDIXuvKQQDMUU4
EPjRGmS89Hl8UKAN0Cq/C1T+OGzn4zrbE06CO/Sm3SRMP24HyIbElhlWV49sfLR05Qmh9fRl1s7
ZdcUrxkDkr2J6on5cMVB9M2nIl90IhRVLd5RxP01u81yqvhvE61ORdA6IMjzXcQ8ebuD2R733O3
7oGFD7e2O7DaabKKkHZIduL/zFbQkzMDK6uAMP8ylRJN0fUsqIhHhtc//16OT2H6nMU09MccxZT
FUfqF8xIOndElP6um4jXYk5Q30i/CtU3TZyvNeWVwyGwDi4wg2jeVe0YHU2Rh/ZcZpwAAAQEAv2
O86701U9sIuRijp8sO4h13eZrsE5rdn6aul/mkm+xAlO+WQeDXR/ONm9BwVSrNEmIJB74tEJL3q
QTMEFoCoN9Kp00Ya7Qt8n4gZ0vcZlI5u+cgyd1mKaggS2SnoorsRlb2Lh/Hpe6mXus8pUTf5QT8
apgXM3TgFsLDT+3rCt40IdGCZLaP+UDBuNUSKfFwCru6uGoXEwxaL08Nv1wZOc19qrc0Yzp7i33
m6i3a0Z9Pu+TPHqYC74QmBbWq8U9DAo+7yhRIhq/fdJzk3vIKSLbCxg4PbMwx2Qfh4dLk+L7wOa
sKnl5//W+RWBUrOlaZ1ZP1/azsK0Ncygno/0F1ew== Voici ma nouvelle cle

Ensuite, excutez votre commande et constatez le rsultat :


$ ssh hote_distant 'ls -l /etc'
La commande etait : ls -l /etc

Cette approche a pour inconvnient dempcher le fonctionnement dun programme


comme rsync qui dpend dun canal STDOUT/STDIN rserv.

2. Nous remercions Richard Silverman et Daniel Barrett pour leurs ides et leurs excellentes
explications dans les livres SSH, le shell scuris La rfrence (ditions OReilly), en particulier
les chapitres 2, 6 et 11, et Linux Security Cookbook (OReilly Media), qui ont normment profit
cette recette.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

330

Chapitre 14 Scripts scuriss

$ rsync -avzL -e ssh hote_distant:/etc .


protocol version mismatch -- is your shell clean?
(see the rsync man page for an explanation)
rsync error: protocol incompatibility (code 2) at compat.c(64)

Nous pouvons contourner ce problme en modifiant la commande force :


command="/bin/echo La commande etait : $SSH_ORIGINAL_COMMAND >>
~/ssh_command"

Nous effectuons un nouveau test du ct client :


$ rsync -avzL -e ssh 192.168.99.56:/etc .
rsync: connection unexpectedly closed (0 bytes received so far) [receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(420)

Voici ce que nous obtenons sur lhte distant :


$ cat ../ssh_command
La commande etait : rsync --server --sender -vlLogDtprz . /etc

Il est donc possible de mettre jour la commande force selon les besoins.
Nous pouvons galement dfinir une restrictions dhte dorigine et dsactiver des commandes SSH. La restriction dhte prcise le nom ou ladresse IP de lhte dorigine. La
dsactivation de certaines commandes est galement assez intuitive :
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty

En runissant le tout, nous obtenons lentre suivante (toujours sur une seule trs longue ligne) :
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,nopty,from="client_local",command="rsync --server --sender -vlLogDtprz . /etc"
ssh-dss
AAAAB3NzaC1kc3MAAAEBANpgvvTslst2m0ZJA0ayhh1Mqa3aWwU3kfv0m9+myFZ9veFsxM7IVxI
jWfAlQh3jplY+Q78fMzCTiG+ZrGZYn8adZ9yg5/wAC03KXm2vKt8LfTx6I+qkMR7v15NI7tZyhx
Gah5qHNehReFWLuk7JXCtRrzRvWMdsHc/L2SA1Y4fJ9Y9FfVlBdE1Er+ZIuc5xIlO6D1HFjKjt3
wjbAal+oJxwZJaupZ0Q7N47uwMslmc5ELQBRNDsaoqFRKlerZASPQ5P+AH/+Cxa/fCGYwsogXSJ
J0H5S7+QJJHFze35YZI/+A1D3BIa4JBf1KvtoaFr5bMdhVAkChdAdMjo96xhbdEAAAAVAJSKzCE
srUo3KAvyUO8KVD6e0B/NAAAA/3u/Ax2TIB/M9MmPqjeH67Mh5Y5NaVWuMqwebDIXuvKQQDMUU4
EPjRGmS89Hl8UKAN0Cq/C1T+OGzn4zrbE06CO/Sm3SRMP24HyIbElhlWV49sfLR05Qmh9fRl1s7
ZdcUrxkDkr2J6on5cMVB9M2nIl90IhRVLd5RxP01u81yqvhvE61ORdA6IMjzXcQ8ebuD2R733O3
7oGFD7e2O7DaabKKkHZIduL/zFbQkzMDK6uAMP8ylRJN0fUsqIhHhtc//16OT2H6nMU09MccxZT
FUfqF8xIOndElP6um4jXYk5Q30i/CtU3TZyvNeWVwyGwDi4wg2jeVe0YHU2Rh/ZcZpwAAAQEAv2
O86701U9sIuRijp8sO4h13eZrsE5rdn6aul/mkm+xAlO+WQeDXR/ONm9BwVSrNEmIJB74tEJL3q
QTMEFoCoN9Kp00Ya7Qt8n4gZ0vcZlI5u+cgyd1mKaggS2SnoorsRlb2Lh/Hpe6mXus8pUTf5QT8
apgXM3TgFsLDT+3rCt40IdGCZLaP+UDBuNUSKfFwCru6uGoXEwxaL08Nv1wZOc19qrc0Yzp7i33
m6i3a0Z9Pu+TPHqYC74QmBbWq8U9DAo+7yhRIhq/fdJzk3vIKSLbCxg4PbMwx2Qfh4dLk+L7wOa
sKnl5//W+RWBUrOlaZ1ZP1/azsK0Ncygno/0F1ew== Voici ma nouvelle cle

Discussion
Si vous rencontrez des difficults avec ssh, loption -v sera trs utile. ssh -v ou ssh -v
-v donne des informations sur les dysfonctionnements. Testez-les avec une configuration oprationnelle afin de connatre laspect de leur sortie.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

14.23. Dconnecter les sessions inactives

331

Si vous souhaitez tre un peu plus ouvert sur les possibilits dune cl, tournez-vous vers
rssh, le shell restreint dOpenSSH (http://www.pizzashack.org/rssh/), qui prend en charge
scp, sftp, rdist, rsync et cvs.
Vous auriez pu croire que les restrictions de ce type taient trs simples, mais ce nest pas
le cas. Le problme vient du fonctionnement de SSH (et des commandes r avant
lui). Il sagit dun outil brillant, qui fonctionne trs bien, mais il est difficile limiter. Si
lon veut extrmement simplifier son fonctionnement, vous pouvez voir SSH comme
une connexion entre le STDOUT local et le STDIN distant, ainsi quune connexion entre le STDOUT distant et le STDIN local. Par consquent, les commandes comme scp et
rsync ne font quenvoyer des octets de la machine locale vers la machine distante, un peu
la manire dun tube. Malheureusement, cette souplesse empche SSH de limiter les
accs interactifs tout en acceptant scp. Cest galement la raison pour laquelle vous ne
pouvez placer des commandes echo et des instructions de dbogage dans les fichiers de
configuration de bash (voir la recette 16.19, page 414). En effet, les messages affichs seraient alors mlangs au flux doctets et provoqueraient des dgts.
Dans ce cas, comment rssh fonctionne-t-il ? Il fournit une enveloppe utilise la place
du shell par dfaut (comme bash) dans /etc/passwd. Cette enveloppe dtermine ce qui est
autoris, mais avec beaucoup plus de souplesse quune commande SSH restreinte.

Voir aussi

SSH, le shell scuris La rfrence de Richard E. Silverman et Daniel J. Barrett (ditions OReilly) ;

Linux Security Cookbook de Daniel J. Barrett et autres (OReilly Media) ;

la recette 14.21, Utiliser SSH sans mot de passe, page 321 ;

la recette 16.19, Crer des fichiers dinitialisation autonomes et portables, page 414.

14.23. Dconnecter les sessions inactives


Problme
Vous souhaitez dconnecter automatiquement les utilisateurs inactifs, en particulier
root.

Solution
Dans /etc/bashrc ou ~/.bashrc, fixez la variable denvironnement $TMOUT au nombre de
secondes dinactivit avant la clture de la session. En mode interactif, aprs laffichage
dune invite, si lutilisateur ne saisit pas une commande dans les $TMOUT secondes, bash
se termine.

Discussion
$TMOUT est galement utilise par les commandes internes read et select dans les
scripts.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

332

Chapitre 14 Scripts scuriss

Noubliez pas de dfinir cette variable dans un fichier systme, comme /etc/profile ou
/etc/bashrc, auxquels les utilisateurs nont pas accs en criture. Ainsi, ils nauront pas la
possibilit de la modifier
declare -r TMOUT=3600
# Ou :
readonly TMOUT=3600
Puisque lutilisateur est matre de son environnement, vous ne pouvez
pas totalement vous appuyer sur $TMOUT, mme dfinie dans un fichier
systme, car il peut simplement excuter un autre shell. Vous devez
voir cette variable comme une aide avec les utilisateurs coopratifs, en
particulier les administrateurs systme qui peuvent tre (souvent) distraits de leur travail.

Voir aussi

la recette 16.19, Crer des fichiers dinitialisation autonomes et portables, page 414.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15
Scripts labors

Unix et POSIX promettent depuis trs longtemps compatibilit et portabilit, mais elles
sont plutt longues venir. Pour les dveloppeurs, lcriture de scripts labors portables, cest--dire qui fonctionnent sur toute machine possdant bash, reprsente donc un
problme important. crire des scripts compatibles avec diffrentes plates-formes savre beaucoup plus complexe quon ne le voudrait. Chaque systme comporte ses petites
variantes qui compliquent les rgles. Par exemple, bash lui-mme nest pas toujours install au mme endroit et de nombreuses commandes Unix classiques possdent des options lgrement diffrentes (ou produisent une sortie lgrement diffrente) en
fonction du systme dexploitation. Dans ce chapitre, nous examinons plusieurs de ces
problmes et donnons leurs solutions.
Par ailleurs, certaines oprations ne savrent pas aussi simples quon le souhaiterait.
Nous allons donc galement prsenter des solutions pour certains scripts labors, comme lautomatisation de processus, lenvoi de courrier lectronique, la journalisation
avec syslog, lutilisation des ressources rseau et quelques astuces concernant la lecture
de lentre et la redirection de la sortie.
Bien que ce chapitre concerne des scripts labors, nous insistons sur limportance
dcrire un code clair, aussi simple que possible et bien document. Brian Kernighan,
lun des premiers dveloppeurs Unix, a trs bien expliqu cet aspect :
Le dbogage est deux fois plus complexe que lcriture initiale du code. Par consquent, si vous crivez le code aussi intelligemment que possible, vous ntes, par dfinition, pas assez intelligent pour le dboguer.

Il est trs facile dcrire des scripts shell trs astucieux et trs difficiles, voire impossibles,
comprendre. Plus vous serez ingnieux le jour de lcriture du code, plus vous le regretterez six, douze ou dix-huit mois aprs, lorsque vous devrez rsoudre un problme
de votre code (ou, pire encore, celui dun autre dveloppeur). Si vous devez tre astucieux, vous devez, pour le moins, documenter le fonctionnement du script (voir la recette 5.1, page 87) !

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

334

Chapitre 15 Scripts labors

15.1. Trouver bash de manire portable


Problme
Vous devez excuter un script bash sur plusieurs machines, mais bash ne se trouve pas
toujours au mme endroit (voir la recette 1.11, page 21).

Solution
Utilisez la commande /usr/bin/env dans la ligne shebang, par exemple #!/usr/bin/env
bash. Si, sur votre systme, la commande env ne se trouve pas dans /usr/bin, demandez
votre administrateur de linstaller, de la dplacer ou de crer un lien symbolique, car
il sagit de lemplacement obligatoire. Par exemple, Red Hat a choisi, sans raison valable,
/bin/env, mais a pris soin dajouter un lien symbolique lemplacement correct.
Vous pouvez galement crer des liens symboliques pour bash lui-mme, mais lemploi
de env constitue la bonne solution.

Discussion
Le rle de env est dexcuter un programme dans un environnement modifi , mais,
puisquelle recherche dans le chemin la commande indique, elle est parfaitement
adapte cette utilisation.
Vous pourriez tre tent par #!/bin/sh. Ny succombez pas. Si vos scripts utilisent des
fonctionnalits propres bash, ils ne fonctionneront pas sur les machines pour qui
/bin/sh nest pas bash en mode shell Bourne (par exemple, BSD, Solaris, Ubuntu 6.10+).
Par ailleurs, mme si, pour le moment, vous nutilisez pas de fonctionnalits spcifiques
bash, vous risquez doublier plus tard cette contrainte. Si vous vous limitez uniquement aux fonctionnalits POSIX, utilisez alors #!/bin/sh (et ne dveloppez pas sur
Linux, voir la recette 15.3, page 337). Dans tous les autres cas, soyez prcis.
Parfois, vous verrez quune espace spare #! et /bin/xxx. La raison en est historique. Si
certains systmes exigeaient cette espace, ce nest plus vraiment le cas aujourdhui. Il est
peu probable quun systme disposant de bash aura besoin de cette espace et elle est
donc gnralement supprime. Mais, pour garantir une rtro-compatibilit, utilisez-la.
Nous avons choisi #!/usr/bin/env bash dans les scripts et les fonctions les plus longues
disponibles en tlchargement (voir la fin de la prface), car cette ligne est compatible
avec la majorit des systmes. Cependant, puisque env se sert de la variable $PATH pour
trouver bash, cela peut reprsenter un problme de scurit (voir la recette 14.2, page
294), quoique mineur, notre avis.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.2. Dfinir une variable $PATH de type POSIX

335

Il est assez surprenant de constater que le traitement de la ligne shebang nest pas cohrent entre les systmes, alors que nous employons
env pour des questions de portabilit. De nombreux systmes, y compris Linux, acceptent le passage dun seul argument linterprteur.
Par consquent, #!/usr/bin/env bash - gnre une erreur :
/usr/bin/env: bash -: Aucun fichier ou rpertoire de ce type

En effet, linterprteur est /usr/bin/env et le seul argument autoris


est bash -. Dautres systmes, comme BSD et Solaris, nont pas cette
restriction.
Puisque le caractre - final est une pratique scuritaire courante (voir
la recette 14.2, page 294) et puisquil est reconnu uniquement sur certains systmes, il sagit l dun problme de scurit et de portabilit.
Vous pouvez utiliser le caractre - final pour amliorer sensiblement la
scurit, mme en rduisant la portabilit, ou inversement. Puisque, de
toute manire, env consulte le chemin, vous devez viter de lemployer
si la scurit est un aspect important. Par consquent, la non-portabilit de - est tolrable.
Nous vous conseillons donc domettre le caractre - final lorsque que
vous employez env pour des raisons de portabilit et de prciser explicitement linterprteur et le caractre - final lorsque la scurit est primordiale.

Voir aussi

les pages web suivantes pour plus dinformations sur la ligne shebang (/usr/bin/env) :
http://srfi.schemers.org/srfi-22/mail-archive/msg00069.html ;
http://www.in-ulm.de/~mascheck/various/shebang/ ;
http://homepages.cwi.nl/~aeb/std/hashexclam-1.html ;
http://www.faqs.org/faqs/unix-faq/faq/part3/, section 3.16 ( Why do some scripts
start with #! ... ? ).

la recette 1.11, Obtenir bash pour xBSD, page 21 ;

la recette 15.2, Dfinir une variable $PATH de type POSIX, page 335 ;

la recette 15.3, Dvelopper des scripts shell portables, page 337 ;

la recette 15.6, crire une commande echo portable, page 342.

15.2. Dfinir une variable $PATH de type


POSIX
Problme
La machine que vous utilisez dispose doutils anciens ou propritaires (par exemple, Solaris) et vous devez dfinir votre PATH de manire accder aux outils POSIX.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

336

Chapitre 15 Scripts labors

Solution
Utilisez getconf :
PATH=$(PATH=/bin:/usr/bin getconf PATH)

Voici quelques chemins par dfaut compatibles POSIX pour diffrents systmes :
# Red Hat Enterprise Linux (RHEL) 4.3
$ echo $PATH
/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/$USER/b
in
$ getconf PATH
/bin:/usr/bin

# Debian Sarge
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
$ getconf PATH
/bin:/usr/bin

# Solaris 10
$ echo $PATH
/usr/bin:
$ getconf PATH
/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin

# OpenBSD 3.7
$ echo $PATH
/home/$USER/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin
:/usr/local/sbin:/usr/games
$ getconf PATH
/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin

Discussion
getconf se fonde sur diffrentes variables de configuration du systme. Vous pouvez donc
vous en servir pour dfinir un chemin par dfaut. Cependant, si getconf nest pas une
commande interne, vous aurez besoin dun chemin minimal pour la trouver. Cest la
raison dtre de PATH=/bin:/usr/bin dans la solution.
En thorie, la variable utiliser est CS_PATH. En pratique, PATH fonctionne sur toutes nos
machines de test, alors que CS_PATH a chou sur les systmes BSD.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.3. Dvelopper des scripts shell portables

337

Voir aussi

http://www.unixreview.com/documents/s=7781/uni1042138723500/ ;

la recette 9.11, Retrouver un fichier partir dune liste demplacements possibles, page
202 ;

la recette 14.3, Dfinir une variable $PATH sre, page 294 ;

la recette 14.9, Trouver les rpertoires modifiables mentionns dans $PATH, page 300 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303 ;

la recette 16.3, Modifier dfinitivement $PATH, page 376 ;

la recette 16.4, Modifier temporairement $PATH, page 377 ;

la recette 19.3, Oublier que le rpertoire de travail nest pas dans $PATH, page 488.

15.3. Dvelopper des scripts shell portables


Problme
Vous souhaitez crire un script shell qui doit sexcuter sur diffrentes versions des diffrents systmes dexploitation Unix ou POSIX.

Solution
Tout dabord, essayez la commande interne command avec son option -p pour trouver
la version POSIX dun programme, par exemple dans /usr/xpg4 ou /usr/xpg6 sur Solaris :
$ command -p programme args

Ensuite, si possible, prenez la machine Unix la plus ancienne ou la moins performante,


et dveloppez le script sur cette plate-forme. Si vous ntes pas certain de la plate-forme
la moins performante, choisissez une variante BSD ou Solaris (dans une version la plus
ancienne possible).

Discussion
command -p utilise un chemin par dfaut qui permet de trouver les utilitaires POSIX
standard. Si vous tes certain que votre script sera toujours excut sur Linux, ne vous
proccupez pas de cet aspect. Sinon, vitez de dvelopper des scripts multi-plateformes
sur Linux ou Windows (par exemple, avec Cygwin).
Voici les problmes lis lcriture de scripts shell multi-plateformes sur Linux :
1. /bin/sh nest pas le shell Bourne, mais /bin/bash en mode Bourne, except lorsquil
sagit de /bin/dash (par exemple, sur Ubuntu 6.10). Si les deux sont trs bons, sans
tre parfaits, aucun des trois ne fonctionne exactement de la mme manire. En
particulier, le comportement de echo peut changer.
2. Linux sappuie sur les outils GNU la place des outils Unix dorigine.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

338

Chapitre 15 Scripts labors

Ne vous mprenez pas. Nous apprcions Linux et lutilisons tous les jours. Mais il ne
sagit pas dun vritable Unix : il fonctionne diffremment et emploie les outils GNU.
Ceux-ci sont extraordinaires et cest bien le problme. Ils disposent dun grand nombre
doptions et de fonctionnalits absentes des autres plates-formes. Par consquent, votre
script se terminera de manire trange, quel que soit le soin que vous lui aurez apport.
En revanche, la compatibilit de Linux est telle que les scripts crits pour dautres systmes de type Unix fonctionneront pratiquement toujours sur ce systme. Ils ne seront
peut-tre pas parfaits (par exemple, le comportement par dfaut de echo est dafficher
un caractre \n la place dun saut de ligne), mais seront gnralement satisfaisants.
En vrit, plus vous utilisez les fonctions du shell, moins vous dpendez de programmes
externes dont lexistence et le comportement ne sont pas garantis. Mme si bash est
beaucoup plus performant que sh, il fait partie des outils qui peuvent tre absents ou
prsents. Une variante de sh existera sur quasiment tous les systmes Unix ou de type
Unix, mais elle ne sera pas toujours celle que vous croyez.
Par ailleurs, si les options longues des outils GNU facilitent la lecture du code, elles ne
sont pas toujours disponiblessur les autres systmes. Ainsi, au lieu dcrire sort
--field-separator=, fichier_non_tri > fichier_tri, vous devez employer sort
-t, fichier_non_tri > fichier_tri pour amliorer la portabilit.
Ne soyez pas dcourag. Le dveloppement sur des systmes non-Linux est plus facile
que jamais. Si vous disposez dj de tels systmes, ce nest videmment pas un problme.
Dans le cas contraire, il est aujourdhui facile de les obtenir gratuitement. Solaris et les
systmes BSD fonctionnent tous dans des environnements virtuels, comme VMware
Player ou Server (gratuits), disponibles pour Windows et Linux (bientt pour Mac).
Si vous disposez dun Macintosh sous OS X, vous utilisez dj un systme BSD.
Vous pouvez galement tester facilement des scripts dans un environnement virtuel
comme VMware (voir la recette 15.4, page 339). En revanche, cette solution nest pas envisageable avec les systmes de type AIX et HP-UX car ils sont incompatibles avec une
architecture x86 et ne fonctionnent donc pas sous VMware. Une fois encore, si vous disposez de ces systmes, utilisez-les. Sinon, consultez la recette 1.15, page 25.

Voir aussi

help command ;

http://fr.wikipedia.org/wiki/Dash ;

http://fr.wikipedia.org/wiki/Bourne-Again_shell ;

http://www.opensolaris.org/os/article/2006-02-27_getting_started_with_opensolaris_
using_vmware/ ;

http://www.testdrive.hp.com/os/ ;

http://www.testdrive.hp.com/faq/ ;

http://www.polarhome.com/ ;

http://www.faqs.org/faqs/hp/hpux-faq/preamble.html ;

lhistoire dUnix, http://www.levenez.com/unix/ ;

la recette 1.15, Obtenir bash sans linstaller, page 25 ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.4. Tester des scripts sous VMware

339

la recette 15.4, Tester des scripts sous VMware, page 339 ;

la recette 15.6, crire une commande echo portable, page 342 ;

la section Options et squences dchappement de echo, page 539.

15.4. Tester des scripts sous VMware


Problme
Vous devez dvelopper des scripts multi-plateformes, mais vous ne disposez pas des systmes ou du matriel adquats.

Solution
Si les plates-formes cibles fonctionnent sur larchitecture x86, tlchargez le logiciel
gratuit VMware Server et installez-les. Vous pouvez galement trouver des machines
virtuelles prconfigures sur le site de VMware, le site du distributeur ou du fournisseur
du systme dexploitation ou sur Internet.
Cette solution est incompatible avec les systmes comme AIX et HP-UX qui ne fonctionnent pas sur une architecture x86 et donc pas sous VMware. Une fois encore, si vous disposez de ces systmes, utilisez-les. Sinon, consultez la recette 1.15, page 25.

Discussion
Le test des scripts shell nest gnralement pas une opration gourmande en ressources.
Un matriel dentre de gamme, capable dexcuter VMware ou un autre outil de virtualisation similaire, fera donc laffaire. Nous citons VMware, car ses versions Server et
Player sont gratuites, fonctionnent avec Linux et Windows (bientt avec Mac) et sont
trs simples utiliser. Il existe certainement dautres solutions.
Si vous installez VMware Server sur un serveur Linux, vous naurez mme pas besoin
de linterface graphique sur la machine hte. Vous pouvez utiliser la console VMware
de type VNC partir dune autre machine Linux ou Windows, sans linterface graphique. Pour un shell de test, une machine virtuelle avec 128 Mo de RAM, parfois moins,
sera suffisante. Configurez un partage NFS afin dy enregistrer les scripts et les donnes
de tests, puis connectez-vous au systme de test par telnet ou, mieux, SSH.
Pour vous aider, voici un exemple simple bas sur VMware Player :
1. Tlchargez le logiciel gratuit VMware Player pour Windows ou Linux partir de
http://www.vmware.com/fr/products/player/.
2. Obtenez limage dune machine virtuelle prconfigure :
a. Ubuntu Linux 5.10 (driv de Debian), Firefox 1.0.7 et Gnome 2.12.1 constitutuent la base du botier virtuel Browser Appliance v1.0.0 de VMware
(258 Mo http://www.vmware.com/vmtn/appliances/directory/browserapp.html).
b. PC-BSD est une distribution bureautique base sur BSD et KDE (718 Mo
http://www.pcbsd.org/?p=download#vmware).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

340

Chapitre 15 Scripts labors

3. Dcompressez le fichier tlcharg et ouvrez-le dans VMware Player, en crant un


nouvel identifiant unique si cela vous est demand.
Aprs le dmarrage, qui peut prendre du temps, vous obtenez un systme Ubuntu 5.10
avec Gnome et bash 3.0 ou bien un systme BSD avec KDE avec bash 3.1 (au moment
de lcriture de ces lignes). Vous pouvez galement excuter deux instances de VMware
Player (ou utiliser VMware Server) pour disposer des deux environnements. Notez que
ces deux distributions utilisent une interface graphique et demandent donc beaucoup
plus de mmoire et de puissance processeur quune installation minimale du shell. Elles
sont mentionnes ici pour servir dexemples. Malgr leurs besoins en ressources, elles
sont particulirement utiles car il sagit dimages officielles et non dimages communautaires dont la qualit et la fiabilit peuvent varier.
Le botier virtuel Browser Appliance de VMware dispose des outils
VMware, contrairement PC-BSD. Ces deux systmes se comporteront donc de manire lgrement diffrente vis--vis de la capture du
clavier et de la souris de la machine hte. Prtez attention au message
affich dans le coin infrieur gauche de la fentre de VMware Player.

Pour plus dinformations sur les possibilits de VMware, consultez Google et les forums
de VMware.

Voir aussi

http://www.vmware.fr/ ;

http://www.vmware.com/fr/products/player/ ;

http://www.vmware.com/vmtn/appliances/ ;

http://www.vmware.com/support/ws55/doc/new_guest_tools_ws.html ;

http://www.ubuntu.fr/ ;

http://www.pcbsd.org/ ;

la recette 1.11, Obtenir bash pour xBSD, page 21 ;

la recette 1.15, Obtenir bash sans linstaller, page 25.

15.5. crire des boucles portables


Problme
Vous devez crire une boucle for, mais souhaitez quelle soit compatible avec les anciennes versions de bash.

Solution
La mthode suivante fonctionne avec les versions de bash-2.04+ :
$ for ((i=0; i<10; i++)); do echo $i; done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.5. crire des boucles portables

341

0
1
2
3
4
5
6
7
8
9

Discussion
Les versions rcentes de bash acceptent dautres critures plus plaisantes de cette boucle,
mais elles ne sont pas rtro-compatibles. Depuis bash-3.0+, vous pouvez employer la syntaxe for {x..y} :
$ for i in {1..10}; do echo $i; done
1
2
3
4
5
6
7
8
9
10

Si votre systme dispose de la commande seq, vous pouvez galement crire :


$ for i in $(seq 1 10); do echo $i; done
1
2
3
4
5
6
7
8
9
10

Voir aussi

help for ;

man seq ;

la recette 6.12, Boucler avec un compteur, page 135 ;

la recette 6.13, Boucler avec des valeurs en virgule flottante, page 136 ;

la recette 17.22, crire des squences, page 469.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

342

Chapitre 15 Scripts labors

15.6. crire une commande echo portable


Problme
Vous crivez un script qui doit sexcuter sur plusieurs versions dUnix et de Linux. Il a
besoin dune commande echo au comportement cohrent, mme lorsque linteprteur
de commandes nest pas bash.

Solution
Utilisez printf "%b" message ou vrifiez le systme et fixez xpg_echo laide de shopt
-s xpg_echo.
Si vous omettez la chane de format "%b" (comme dans printf message), printf tente
dinterprter les caractres % contenus dans message, ce que vous ne souhaitez probablement pas. Le format "%b" est une extension de la commande printf standard qui empche cette mauvaise interprtation et dveloppe galement les squences dchappement
dans message.
La dfinition de xpg_echo est moins cohrente car elle ne fonctione quavec bash. Vous
ouvez lemployer si vous tes certain que linterprteur de commandes sera toujours
bash et non sh ou un autre shell similaire qui ne reconnat pas xpg_echo.
Lutilisation de printf vous oblige remplacer toutes les commandes echo, mais cette instruction est dfinie par POSIX et devrait se comporter de manire cohrente sur tous
les shells POSIX. Plus prcisment, vous devez crire printf "%b" la place de echo.
Si vous crivez $b la place de %b, vous nobtenez pas le rsultat
escompt. Le message affich est vide, car le format est nul, sauf si $b
est dfinie. Dans ce cas, le rsultat dpend de la valeur de $b. Ce bogue
risque dtre difficile trouver, car $b et %b ont une apparence trs
similaire :
$ printf "%b" "OK"
OK
$ printf "$b" "Dysfonctionnement"
$

Discussion
Avec certains shells, la commande interne echo se comporte diffremment du programme externe echo employ par quelques systmes. Sous Linux, cette diffrence nest pas
toujours facile dtecter car /bin/sh est gnralement bash (en gnral, mais il peut galement sagir de dash sur Ubuntu 6.10+) et des cas similaires existent sur certaines versions de BSD. Le comportement diffre dans lexpansion des squences dchappement.
Les commandes echo internes au shell ont tendance ne pas les dvelopper, contrairement aux versions externes (par exemple, /bin/echo et /usr/bin/echo). Mais, une fois encore, cela varie dun systme lautre.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.6. crire une commande echo portable

343

Linux classique (/bin/bash) :


$ type -a echo
echo is a shell builtin
echo is /bin/echo
$ builtin echo "un\tdeux\ntrois"
un\tdeux\ntrois\n
$ /bin/echo "un\tdeux\ntrois"
un\tdeux\ntrois\n
$ echo -e "un\tdeux\ntrois"
undeux
trois
$ /bin/echo -e "un\tdeux\ntrois"
undeux
trois

$ shopt -s xpg_echo
$ builtin echo "un\tdeux\ntrois"
undeux
trois
$ shopt -u xpg_echo
$ builtin echo "un\tdeux\ntrois"
un\tdeux\ntrois\n

BSD classique (/bin/csh, puis /bin/sh) :


$ which echo
echo: shell built-in command.
$ echo "un\tdeux\ntrois"
un\tdeux\ntrois\n
$ /bin/echo "un\tdeux\ntrois"
un\tdeux\ntrois\n
$ echo -e "un\tdeux\ntrois"
-e un\tdeux\ntrois\n
$ /bin/echo -e "un\tdeux\ntrois"
-e un\tdeux\ntrois\n
$ printf "%b" "un\tdeux\ntrois"
undeux
trois

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

344

Chapitre 15 Scripts labors

$ /bin/sh
$ echo "un\tdeux\ntrois"
un\tdeux\ntrois\n
$ echo -e "un\tdeux\ntrois"
undeux
trois
$ printf "%b" "un\tdeux\ntrois"
undeux
trois

Solaris 10 (/bin/sh) :
$ which echo
/usr/bin/echo
$ type echo
echo is a shell builtin
$ echo "un\tdeux\ntrois"
un deux
trois
$ echo -e "un\tdeux\ntrois"
-e undeux
trois
$ printf "%b" "un\tdeux\ntrois"
undeux
trois

Voir aussi

help printf ;

man 1 printf ;

http://www.opengroup.org/onlinepubs/009695399/functions/printf.html ;

la recette 2.3, Mettre en forme la sortie, page 34 ;

la recette 2.4, crire la sortie sans le saut de ligne, page 35 ;

la recette 15.1, Trouver bash de manire portable, page 334 ;

la recette 15.3, Dvelopper des scripts shell portables, page 337 ;

la recette 19.11, Constater un comportement trange de printf, page 497 ;

la section printf, page 540.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.7. Dcouper lentre si ncessaire

345

15.7. Dcouper lentre si ncessaire


Problme
Vous souhaitez dcouper lentre uniquement si son contenu dpasse une certaine limite, mais la commande split cre toujours au moins un nouveau fichier.

Solution
# bash Le livre de recettes : fonc_decouper
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Dcouper l'entre en segments de taille fixe uniquement si elle
# dpasse une certaine limite.
# Usage : Decouper <fichier> <prfixe> <option de limite> <arg de limite>
# Exemple : Decouper $sortie ${sortie}_ --lines 100
# Voir split(1) et wc(1) pour les options.
function Decouper {
local fichier=$1
local prefixe=$2
local type_limite=$3
local taille_limite=$4
local option_wc
# Vrifications initiales.
if [ -z "$fichier" ]; then
printf "%b" "Decouper : nom de fichier absent !\n"
return 1
fi
if [ -z "$prefixe" ]; then
printf "%b" "Decouper : prfixe du fichier de sortie absent !\n"
return 1
fi
if [ -z "$type_limite" ]; then
printf "%b" "Decouper : option de limite (ex. --lines) absente, voir
'man split' !\n"
return 1
fi
if [ -z "$taille_limite" ]; then
printf "%b" "Decouper : taille de limite (ex. 100) absente, voir 'man
split' !\n"
return 1
fi
# Convertir les options de split en option de wc. Toutes les options
# ne sont pas reconnues par wc/split sur tous les systmes.
case $type_limite in
-b|--bytes)
option_wc='-c';;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

346

Chapitre 15 Scripts labors


-C|--line-bytes) option_wc='-L';;
-l|--lines)
option_wc='-l';;
esac

# Si la limite est dpasse.


if [ "$(wc $option_wc $fichier | awk '{print $1}')" -gt $taille_limite ];
then
# Faire quelque chose.
split --verbose $type_limite $taille_limite $fichier $prefixe
fi
} # Fin de la fonction Decouper.

Discussion
En fonction de votre systme, certaines options (par exemple, -C) ne seront peut-tre
pas disponibles pour split ou wc.

Voir aussi

recette 8.13, Compter les lignes, les mots ou les caractres dans un fichier, page 187.

15.8. Afficher la sortie en hexadcimal


Problme
Vous souhaiter examiner la sortie en mode hexadcimal afin de vrifier la prsence
dun caractre despacement ou non imprimable.

Solution
Dirigez la sortie vers hexdump et utilisez loption -C pour obtenir une sortie canonique :
$ hexdump
00000000
00000010
00000020
0000002c

-C
4c
0a
0a

nom_fichier
69 67 6e 65 20 31 0a
4c 69 67 6e 65 20 34
0a 4c 69 67 6e 65 20

4c 69 67 6e 65 20 32 0a
0a 4c 69 67 6e 65 20 35
36 0a 0a 0a

|Ligne 1.Ligne 2.|


|.Ligne 4.Ligne 5|
|..Ligne 6...|

Par exemple, nl insre des espaces (code ASCII 20), puis le numro de ligne, puis une
tabulation (code ASCII 09) :
$ nl -ba nom_fichier | hexdump
00000000 20 20 20 20 20 31 09
00000010 20 20 20 20 32 09 4c
00000020 20 20 20 33 09 0a 20
00000030 6e 65 20 34 0a 20 20
00000040 65 20 35 0a 20 20 20
00000050 20 37 09 4c 69 67 6e
00000060 38 09 0a 20 20 20 20
0000006b

[05/03/08]

bash Le livre de recettes

-C
4c 69 67 6e 65 20 31
69 67 6e 65 20 32 0a
20 20 20 20 34 09 4c
20 20 20 35 09 4c 69
20 20 36 09 0a 20 20
65 20 36 0a 20 20 20
20 39 09 0a

0a
20
69
67
20
20

20 |
1.Ligne 1. |
20 |
2.Ligne 2. |
67 |
3..
4.Lig|
6e |ne 4.
5.Lign|
20 |e 5.
6..
|
20 | 7.Ligne 6.
|
|8..
9..|

Elodie FRITSCH <elodie.fritsch@total.com>

15.8. Afficher la sortie en hexadcimal

347

Discussion
hexdump est un utilitaire BSD disponible galement sur de nombreux distributions
Linux. Sur dautres systmes, en particulier Solaris, il nest pas install par dfaut. Vous
pouvez obtenir un affichage en octal avec la commande od, mais le rsultat est plus difficile lire :
$ nl -ba nom_fichier |
0000000 2020 2020 3120
0000020 2020 2020 0932
0000040 2020 3320 0a09
0000060 656e 3420 200a
0000100 2065 0a35 2020
0000120 3720 4c09 6769
0000140 0938 200a 2020
0000153

od -x
4c09 6769
694c 6e67
2020 2020
2020 2020
2020 3620
656e 3620
2020 0939

$ nl -ba nom_fichier |
0000000 20 20 20 20 20
0000020 20 20 20 20 32
0000040 20 20 20 33 09
0000060 6e 65 20 34 0a
0000100 65 20 35 0a 20
0000120 20 37 09 4c 69
0000140 38 09 0a 20 20
0000153

od
31
09
0a
20
20
67
20

-tx1
09 4c
4c 69
20 20
20 20
20 20
6e 65
20 20

656e
2065
3420
0935
0a09
200a
000a

69
67
20
20
20
20
39

67
6e
20
20
36
36
09

3120
0a32
4c09
694c
2020
2020

6e
65
20
35
09
0a
0a

65
20
34
09
0a
20

200a
2020
6769
6e67
2020
2020

20
32
09
4c
20
20

31
0a
4c
69
20
20

0a
20
69
67
20
20

20
20
67
6e
20
20

Il existe galement un script Perl simple que vous pourrez trouver http://www.khngai.
com/perl/bin/hexdump.txt :
$ ./hexdump.pl nom_fichier
/0 /1
0000 : 4C 69
0010 : 0A 4C
0020 : 0A 0A

/2
67
69
4C

/3
6E
67
69

/4
65
6E
67

/5
20
65
6E

/6
31
20
65

/7
0A
34
20

/8
4C
0A
36

/9/ A
69 67
4C 69
0A 0A

/B /C /D /E /F
6E 65 20 32 0A
67 6E 65 20 35
0A

0123456789ABCDEF
Ligne 1.Ligne 2.
.Ligne 4.Ligne 5
..Ligne 6...

Voir aussi

man hexdump ;

man od ;

http://www.khngai.com/perl/bin/hexdump.txt ;

http://gnuwin32.sourceforge.net/packages/hextools.htm ;

la section Tableau des valeurs ASCII, page 555.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

348

Chapitre 15 Scripts labors

15.9. Utiliser la redirection du rseau de bash


Problme
Vous souhaitez envoyer ou recevoir du trafic rseau trs simple, mais vous ne disposez
daucun outil du type netcat.

Solution
Si votre version de bash (2.04+) a t compile avec loption --enable-net-redirections (ce nest pas le cas sous Debian et ses variantes), vous pouvez lutiliser directement. Lexemple suivant est galement donn la recette 15.10, page 349 :
$ exec 3<> /dev/tcp/www.ippages.com/80
$ echo -e "GET /simple/?se=1 HTTP/1.0\n" >&3
$ cat <&3
HTTP/1.1 200 OK
Date: Tue, 28 Nov 2006 08:13:08 GMT
Server: Apache/2.0.52 (Red Hat)
X-Powered-By: PHP/4.3.9
Set-Cookie: smipcomID=6670614; expires=Sun, 27-Nov-2011 08:13:09 GMT; path=/
Pragma: no-cache
Cache-Control: no-cache, must-revalidate
Content-Length: 125
Connection: close
Content-Type: text/plain; charset=ISO-8859-1
72.NN.NN.225 (US-United States) http://www..com Tue, 28 Nov 2006 08:13:09
UTC/GMT
flagged User Agent - reduced functionality
Comme nous lavons mentionn, cette solution ne fonctionnera probablement pas sous Debian et ses variantes, comme Ubuntu, puisque ces
distributions ne compilent pas bash avec --enable-net-redirections.

Discussion
Comme lexplique la recette 15.12, page 356, il est possible dutiliser exec pour rediriger
de manire permanente des descripteurs de fichiers au sein de la session shell en cours.
La premire commande place lentre et la sortie sur le descripteur de fichier 3. La
deuxime ligne envoie une commande simple au serveur web indiqu sur la premire
ligne. Notez que lagent utilisateur apparatra sous la rfrence "-" du ct du serveur
web, do lavertissement flagged User Agent . La troisime commande affiche simplement le rsultat.
Les protocoles TCP et UDP sont tous deux pris en charge. Voici un exemple simple denvoi de messages syslog un serveur distant (pour une utilisation relle, nous vous conseillons demployer logger, qui est beaucoup plus convivial et robuste) :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.10. Dterminer mon adresse

349

echo "<133>$0[$$]: Test de message syslog depuis bash" >


/dev/udp/loghost.exemple.fr/514

PuisquUDP est un protocole de type datagramme, lexemple est beaucoup plus simple
que celui bas sur TCP. <133> correspond la valeur de priorit syslog pour local0.notice,
calcule conformment la RFC 3164. Consultez la RFC 4.1.1 PRI Part et la page
de manuel de logger. $0 est le nom et $$ lidentifiant de processus du programme en
cours. Ce nom sera -bash pour le shell de connexion.

Voir aussi

man logger ;

la RFC 3164 : The BSD Syslog Protocol, http://www.faqs.org/rfcs/rfc3164.html ;

la recette 15.10, Dterminer mon adresse, page 349 ;

la recette 15.12, Rediriger la sortie pour toute la dure dun script, page 356 ;

la recette 15.14, Journaliser vers syslog depuis un script, page 359 ;

lannexe B, Exemples fournis avec bash, page 559, plus particulirement ./functions/
gethtml.

15.10. Dterminer mon adresse


Problme
Vous souhaitez connatre ladresse IP de votre machine.

Solution
Il nexiste aucune bonne manire dobtenir cette information qui fonctionnera sur tous
les systmes dans tous les cas. Nous prsenterons donc plusieurs solutions possibles.
Premirement, vous pouvez analyser la sortie produite par ifconfig afin dy trouver des
adresses IP. Les exemples suivants retournent la premire adresse IP qui ne correspond
pas une boucle de retour ou rien si aucune interface nest configure ou active.
# bash Le livre de recettes : trouver_ip
# IPv4 - avec awk, cut et head.
$ /sbin/ifconfig -a | awk '/(cast)/ { print $2 }' | cut -d':' -f2 | head -1
# IPv4 - avec Perl, juste pour le plaisir.
$ /sbin/ifconfig -a | perl -ne 'if ( m/^\s*inet (?:addr:)?([\d.]+).*?cast/ )
{ print qq($1\n); exit 0; }'

# IPv6 - avec awk, cut et head.


$ /sbin/ifconfig -a | egrep 'inet6 addr: |address: ' | cut -d':' -f2- | cut
-d'/' -f1 | head -1 | tr -d ' '

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

350

Chapitre 15 Scripts labors

# IPv6 - avec Perl, juste pour le plaisir.


$ /sbin/ifconfig -a | perl -ne 'if ( m/^\s*(?:inet6)? \s*addr(?:ess)?: ([09A-Fa-f:]+)/ ) { print qq($1\n); exit 0; }'

Deuximement, vous pouvez obtenir votre nom dhte et en dduire une adresse IP.
Cette solution est peu fiable car les systmes actuels, en particulier les stations de travail,
peuvent avoir des noms dhte incomplets ou incorrects et/ou se trouver sur un rseau
dynamique qui noffre pas une recherche inverse adquate. Utilisez-la en connaissance
de cause.
$ host $(hostname)

Troisimement, vous tes peut-tre plus intress par ladresse externe routable de votre
machine que par son adresse interne (RFC 1918). Dans ce cas, vous pouvez employer un
hte externe, comme http://www.ippages.com/ ou FollowMeIP (voir ci-aprs) pour
connatre ladresse de votre pare-feu ou de votre priphrique NAT. Linconvnient de
cette mthode rside dans le fait que les systmes autres que Linux ne disposent pas toujours dun outil de type wget. lynx ou curl fonctionneront galement, mais, en gnral,
ils ne sont pas installs par dfaut (Mac OS X 10.4 dispose de curl). Notez que ladresse
IP est volontairement masque dans les exemples suivants :
$ wget -qO - http://www.ippages.com/simple/
72.NN.NN.225 (US-United States) http://www.ippages.com Mon, 27 Nov 2006
21:02:23 UTC/GMT
(5 of 199 allowed today)
alternate access in XML format at: http://www.ippages.com/xml
alternate access via SOAP at: http://www.ippages.com/soap/server.php
alternate access via RSS feed at: http://www.ippages.com/rss.php
alternate access in VoiceXML format at: http://www.ippages.com/voicexml
$ wget -qO - http://www.ippages.com/simple/?se=1
72.NN.NN.225 (US-United States) http://www.ippages.com Tue, 28 Nov 2006
08:11:36 UTC/GMT
$ wget -qO - http://www.ippages.com/simple/?se=1 | cut -d' ' -f1
72.NN.NN.225

$ lynx -dump http://www.ippages.com/simple/?se=1 | cut -d' ' -f1


72.NN.NN.225
$ curl -s http://www.ippages.com/simple/?se=1 | cut -d' ' -f1
72.NN.NN.225

Si vous navez pas accs aux programmes prcdents, mais que votre version de bash
(2.04+) a t compile avec --enable-net-redirections (ce nest pas le cas sous Debian
et ses variantes), utilisez le shell lui-mme. Pour plus de dtails, consultez la recette 15.9,
page 348.
$ exec 3<> /dev/tcp/www.ippages.com/80
$ echo -e "GET /simple/?se=1 HTTP/1.0\n" >&3
$ cat <&3
HTTP/1.1 200 OK

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.10. Dterminer mon adresse

351

Date: Tue, 28 Nov 2006 08:13:08 GMT


Server: Apache/2.0.52 (Red Hat)
X-Powered-By: PHP/4.3.9
Set-Cookie: smipcomID=6670614; expires=Sun, 27-Nov-2011 08:13:09 GMT; path=/
Pragma: no-cache
Cache-Control: no-cache, must-revalidate
Content-Length: 125
Connection: close
Content-Type: text/plain; charset=ISO-8859-1
72.NN.NN.225 (US-United States) http://www..com Tue, 28 Nov 2006 08:13:09
UTC/GMT
flagged User Agent - reduced functionality

$ exec 3<> /dev/tcp/www.ippages.com/80


$ echo -e "GET /simple/?se=1 HTTP/1.0\n" >&3
$ egrep '^[0-9.]+ ' <&3 | cut -d' ' -f1
72.NN.NN.225

FollowMeIP est un peu diffrent. Il en existe un client, http://ipserver.fmip.org/,


mais vous nen avez pas rellement besoin. Vous remarquerez que le port utilis nest
pas standard et que cette solution ne fonctionnera pas avec un filtrage en sortie strict
(sur le pare-feu).
# Utiliser telnet.
$ telnet ipserver.fmip.org 42750 2>&1 | egrep '^[0-9]+'
72.NN.NN.225

# Utiliser bash directement (plus facile, si disponible).


$ exec 3<> /dev/tcp/ipserver.fmip.org/42750 && cat <&3
72.NN.NN.225

Discussion
Le code awk et Perl montr dans la premire solution est intressant cause des variantes des systmes dexploitation dcrites ici. Cependant, les lignes qui nous concernent
contiennent toutes Bcast ou broadcast (ou inet6 addr: ou address:)1. Par consquent, une fois ces lignes obtenues, il suffit de les analyser pour trouver le champ voulu.
Bien entendu, Linux nous complique la tche en utilisant un format diffrent.
Tous les systmes nexigent pas la prsence du chemin (si vous ntes pas root) ou un argument -a ifconfig, mais ils lacceptent tous. Dans tous les cas, il est donc prfrable
dinvoquer /sbin/ifconfig -a.
Voici des exemples de sortie de ifconfig provenant de diffrentes machines :

1. N.d.T. : si votre version de ifconfig a t traduite en franais, la sortie contiendra probablement adr: ou adresse:.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

352

Chapitre 15 Scripts labors

# Linux
$ /sbin/ifconfig
eth0
Link encap:Ethernet HWaddr 00:C0:9F:0B:8F:F6
inet addr:192.168.99.11 Bcast:192.168.99.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:33073511 errors:0 dropped:0 overruns:0 frame:827
TX packets:52865023 errors:0 dropped:0 overruns:1 carrier:7
collisions:12922745 txqueuelen:100
RX bytes:2224430163 (2121.3 Mb) TX bytes:51266497 (48.8 Mb)
Interrupt:11 Base address:0xd000
lo

Link encap:Local Loopback


inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:659102 errors:0 dropped:0 overruns:0 frame:0
TX packets:659102 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:89603190 (85.4 Mb) TX bytes:89603190 (85.4 Mb)

$ /sbin/ifconfig
eth0
Link encap:Ethernet HWaddr 00:06:29:33:4D:42
inet addr:192.168.99.144 Bcast:192.168.99.255 Mask:255.255.255.0
inet6 addr: fe80::206:29ff:fe33:4d42/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1246774 errors:14 dropped:0 overruns:0 frame:14
TX packets:1063160 errors:0 dropped:0 overruns:0 carrier:5
collisions:65476 txqueuelen:1000
RX bytes:731714472 (697.8 MiB) TX bytes:942695735 (899.0 MiB)
lo

Link encap:Local Loopback


inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:144664 errors:0 dropped:0 overruns:0 frame:0
TX packets:144664 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:152181602 (145.1 MiB) TX bytes:152181602 (145.1 MiB)

sit0

Link encap:IPv6-in-IPv4
inet6 addr: ::127.0.0.1/96 Scope:Unknown
UP RUNNING NOARP MTU:1480 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:101910 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

# NetBSD
$ /sbin/ifconfig -a
pcn0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
address: 00:0c:29:31:eb:19

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.10. Dterminer mon adresse

353

media: Ethernet autoselect (autoselect)


inet 192.168.99.56 netmask 0xffffff00 broadcast 192.168.99.255
inet6 fe80::20c:29ff:fe31:eb19%pcn0 prefixlen 64 scopeid 0x1
lo0: flags=8009<UP,LOOPBACK,MULTICAST> mtu 33196
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
ppp0: flags=8010<POINTOPOINT,MULTICAST> mtu 1500
ppp1: flags=8010<POINTOPOINT,MULTICAST> mtu 1500
sl0: flags=c010<POINTOPOINT,LINK2,MULTICAST> mtu 296
sl1: flags=c010<POINTOPOINT,LINK2,MULTICAST> mtu 296
strip0: flags=0 mtu 1100
strip1: flags=0 mtu 1100

# OpenBSD, FreeBSD
$ /sbin/ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 33224
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x5
le1: flags=8863<UP,BROADCAST,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST> mtu 1500
address: 00:0c:29:25:df:00
inet6 fe80::20c:29ff:fe25:df00%le1 prefixlen 64 scopeid 0x1
inet 192.168.99.193 netmask 0xffffff00 broadcast 192.168.99.255
pflog0: flags=0<> mtu 33224
pfsync0: flags=0<> mtu 2020

# Solaris
$ /sbin/ifconfig -a
lo0: flags=1000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4> mtu 8232 index 1
inet 127.0.0.1 netmask ff000000
pcn0: flags=1004843<UP,BROADCAST,RUNNING,MULTICAST,DHCP,IPv4> mtu 1500 index
2
inet 192.168.99.159 netmask ffffff00 broadcast 192.168.99.255
# Mac
$ /sbin/ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
inet6 fe80::20d:93ff:fe65:f720%en0 prefixlen 64 scopeid 0x4
inet 192.168.99.155 netmask 0xffffff00 broadcast 192.168.99.255
ether 00:0d:93:65:f7:20
media: autoselect (100baseTX <half-duplex>) status: active
supported media: none autoselect 10baseT/UTP <half-duplex>
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

354

Chapitre 15 Scripts labors

10baseT/UTP <full-duplex> 10baseT/UTP <full-duplex,hw-loopback> 100baseTX


<half-duplex> 100baseTX <full-duplex> 100baseTX <full-duplex,hw-loopback>
fw0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 2030
lladdr 00:0d:93:ff:fe:65:f7:20
media: autoselect <full-duplex> status: inactive
supported media: autoselect <full-duplex>

Voir aussi

man awk ;

man curl ;

man cut ;

man head ;

man lynx ;

man perl ;

man wget ;

http://www.ippages.com/ ou http://www.showmyip.com/ ;

http://ipserver.fmip.org/ ;

http://abcdrfc.free.fr/rfc-vf/rfc1918.html ;

la recette 15.9, Utiliser la redirection du rseau de bash, page 348 ;

la recette 15.12, Rediriger la sortie pour toute la dure dun script, page 356.

15.11. Obtenir lentre depuis une autre


machine
Problme
Votre script doit obtenir son entre depuis une autre machine, peut-tre pour vrifier
si un fichier existe ou si un processus est en cours dexcution.

Solution
Utilisez SSH avec des cls publiques et une substitution de commandes. Pour cela, configurez SSH de manire ne pas entrer un mot de passe, comme lexplique la recette
14.21, page 321. Ensuite, ajustez la commande excute par SSH pour quelle affiche
exactement ce dont votre script a besoin en entre. Puis, utilisez simplement une substitution de commandes.
#!/usr/bin/env bash
# bash Le livre de recettes : subst_commande
HOTE_DISTANT='hote.exeple.fr'
# Requis.
FICHIER_DISTANT='/etc/passwd'
# Requis.
UTILISATEUR_SSH='user@'
# Facultatif, fixer '' pour ne pas utiliser.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.11. Obtenir lentre depuis une autre machine


#ID_SSH='-i ~/.ssh/foo.id'
ID_SSH=''

355

# Facultatif, fixer '' pour ne pas utiliser.

resultat=$(
ssh $ID_SSH $UTILISATEUR_SSH$HOTE_DISTANT \
"[ -r $FICHIER_DISTANT ] && echo 1 || echo 0"
) || { echo "Echec de la commande !" >&2; exit 1; }
if [ $resultat = 1 ]; then
echo "$FICHIER_DISTANT prsent sur $HOTE_DISTANT"
else
echo "$FICHIER_DISTANT absent de $HOTE_DISTANT"
fi

Discussion
Cet exemple sappuie sur plusieurs oprations intressantes. Tout dabord, vous remarquerez le fonctionnement de $UTILISATEUR_SSH et de $ID_SSH. Elles jouent un rle uniquement lorsquelles possdent une valeur, mais sont ignores lorsquelles sont vides.
Cela nous permet de placer ces valeurs dans un fichier de configuration et le code dans
une fonction, ou les deux.
# Ligne rsultante lorsque les variables ont une valeur :
ssh -i ~/.ssh/foo.id user@hote.exemple.fr [...]
# Sans valeur :
ssh hote.exemple.fr [...]

Ensuite, nous configurons la commande excute par SSH afin quil existe toujours une
sortie (0 ou 1), puis nous vrifions que $resultat nest pas vide. Il sagit dune manire
de sassurer que la commande SSH sest excute (voir galement la recette 4.2, page 73).
Si $resultat est vide, nous regroupons la commande dans un bloc de code { } pour afficher un message derreur et quitter le script. Mais, puisque nous obtenons toujours
une sortie de la commande SSH, nous devons tester la valeur. Il nest pas possible dappeler simplement if [ $resultat ]; then.
Si nous nutilisons pas le bloc de code, nous naffichons lavertissement que si la commande SSH a retourn un rsultat vide, mais nous quittons toujours le script. Pour en
comprendre la raison, relisez bien le code. Il est en effet trs facile de tomber dans ce
pige. De mme, si nous utilisons un sous-shell ( ) la place du bloc de code { }, nous
nobtenons pas le rsultat escompt car linstruction exit 1 quitte le sous-shell et non le
script. Celui-ci continue son excution mme aprs lchec de la commande SSH le
code apparat presque correct et ce bogue est difficile trouver.
Le dernier cas de test peut tre crit de la manire suivante. La version employer dpend de votre style et du nombre dinstructions excuter dans chaque situation. Dans
ce cas, cela na pas dimportance.
[ $resultat = 1 ] && echo "$FICHIER_DISTANT prsent sur $HOTE_DISTANT" \
|| echo "$FICHIER_DISTANT absent de $HOTE_DISTANT"

Enfin, nous prenons soin de la mise en forme afin que les lignes ne soient pas trop longues, que le code reste lisible et que notre objectif soit clair.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

356

Chapitre 15 Scripts labors

Voir aussi

la recette 2.14, Enregistrer ou runir la sortie de plusieurs commandes, page 44 ;

la recette 4.2, Connatre le rsultat de lexcution dune commande, page 73 ;

la recette 14.21, Utiliser SSH sans mot de passe, page 321 ;

la recette 17.18, Filtrer la sortie de ps sans afficher le processus grep, page 463 ;

la recette 17.19, Dterminer si un processus sexcute, page 464.

15.12. Rediriger la sortie pour toute la dure


dun script
Problme
Vous souhaitez rediriger la sortie dun script entier sans avoir modifier chaque instruction echo ou printf.

Solution
Utilisez une fonctionnalit peu connue de la commande exec pour rediriger STDOUT
ou STDERR :
# Facultatif, conserver lancienne erreur standard.
exec 3>&2
# Les sorties vers STDERR sont rediriges vers un fichier de
# journalisation des erreurs.
exec 2> /chemin/vers/erreur_log
# Emplacement du script dont lerreur standard est redirige
# de manire globale.
# Dsactiver la redirection en inversant STDERR et en fermant FH3.
exec 2>&3-

Discussion
Normalement, exec remplace le shell en cours dexcution par la commande passe en
argument, dtruisant ainsi le shell dorigine. Cependant, lorsquaucune commande
nest prcise, elle permet de manipuler la redirection du shell en cours. Cette redirection ne se limite pas STDOUT ou STDERR, mais il sagit des deux cibles les plus courantes.

Voir aussi

help exec ;

la recette 15.9, Utiliser la redirection du rseau de bash, page 348.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.13. Contourner les erreurs liste darguments trop longue

357

15.13. Contourner les erreurs liste


darguments trop longue
Problme
Vous recevez une erreur liste darguments trop longue lors de lexcution dune
commande impliquant une expansion des caractres gnriques du shell.

Solution
Utilisez la commande xargs, conjointement find, pour dcomposer la liste des arguments.
Pour les cas simples, remplacez ls par une boucle for ou une commande find :
$ ls /chemin/avec/beaucoup/beaucoup/de/fichiers/*e*
-/bin/bash: /bin/ls: Liste darguments trop longue
# Petite dmonstration. Les caractres ~ servent dillustration.
$ for i in ./des_fichiers/*e*; do echo "~$i~"; done
~./des_fichiers/fichier avec |~
~./des_fichiers/fichier avec ;~
~./des_fichiers/fichier avec :~
~./des_fichiers/fichier avec des espaces~
~./des_fichiers/fichier avec un signe =~
~./des_fichiers/Fichier incluant un
saut de ligne~
~./des_fichiers/fichier normal~
~./des_fichiers/Un fichier avec des [crochets]~
~./des_fichiers/Un fichier avec des (parentheses)~
$ find ./des_fichiers -name '*e*' -exec echo ~{}~ \;
~./des_fichiers/fichier avec ;~
~./des_fichiers/fichier avec des espaces~
~./des_fichiers/fichier normal~
~./des_fichiers/Un fichier avec des [crochets]~
~./des_fichiers/fichier avec :~
~./des_fichiers/fichier avec |~
~./des_fichiers/fichier avec un signe =~
~./des_fichiers/Fichier incluant un
saut de ligne~
~./des_fichiers/Un fichier avec des (parentheses)~
$ for i in /chemin/avec/beaucoup/beaucoup/de/fichiers/*e*; do echo "$i";
done
[Cela fonctionne, mais la sortie est trop longue pour la donner.]

$ find /chemin/avec/beaucoup/beaucoup/de/fichiers/ -name '*e*'


[Cela fonctionne, mais la sortie est trop longue pour la donner.]

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

358

Chapitre 15 Scripts labors

Lexemple prcdent fonctionne parfaitement avec la commande echo, mais lorsque


vous passez "$i" dautres programmes, en particulier dautres constructions du shell,
la variable $IFS et dautres oprations danalyse peuvent entrer en scne. Les outils
GNU find et xargs tiennent compte de ce point avec find -print0 et xargs -0. (Nous ne
savons pas pourquoi les arguments sont -print0 et -0, au lieu dtre cohrents.) Ces arguments indiquent find demployer le caractre nul (qui ne peut apparatre dans un
nom de fichier) la place dun caractre espace comme sparateur des lments de la sortie
et xargs de lutiliser comme sparateur des lments de lentre. Ainsi, mme les fichiers dont les noms contiennent des caractres tranges seront correctement traits.
$ find /chemin/avec/beaucoup/beaucoup/de/fichiers/ -name '*e*' -print0 |
xargs -0 proggy

Discussion
Par dfaut, bash (et sh) retourne tels quels les motifs sans correspondance. Autrement
dit, si aucun fichier ne correspond son motif, la variable $i de la boucle for prend la
valeur ./des_fichiers/*e*. Vous pouvez invoquer shopt -s nullglob pour que les
motifs de noms de fichiers qui ne correspondent aucun fichier deviennent une chane
nulle.
Vous pourriez penser que la boucle for utilise dans le cas simple conduit au mme problme que la commande ls, mais il nen est rien, comme lexplique Chet Ramey :
ARG_MAX fixe la limite sur lespace total utilis par les appels systme de type exec*.
Ainsi, le noyau connat la taille maximale du tampon allouer. Cela concerne les
trois arguments de execve : nom du programme, vecteur des arguments et environnement.
La commande ls choue car le nombre doctet total des arguments de execve dpasse
ARG_MAX. La boucle for russit car tout se fait de manire interne : mme si lintgralit de la liste est gnre et enregistre, execve nest jamais appel.

Faites attention car find pourrait trouver un trs grand nombre de fichiers. En effet, par
dfaut, cette commande parcourt rcursivement tous les sous-rpertoires, contrairement ls. Certaines versions de find disposent dune option -d qui contrle la profondeur de parcours. La boucle for constitue probablement la solution la plus simple.
Pour connatre la taille limite fixe sur votre systme, utilisez la commande getconf
ARG_MAX. Elle varie de manire importante, comme le montre le tableau 15-1 (voir galement getconf LINE_MAX).
Tableau 15-1. Limites du systme
Systme
HP-UX 11

2 048 000

Solaris (8, 9, 10)

1 048 320

NetBSD 2.0.2, OpenBSD 3.7, OS/X

262 144

Linux (Red Hat, Debian, Ubuntu)

131 072

FreeBSD 5.4

65 536

[05/03/08]

bash Le livre de recettes

ARG_MAX (octets)

Elodie FRITSCH <elodie.fritsch@total.com>

15.14. Journaliser vers syslog depuis un script

359

Voir aussi

http://www.gnu.org/software/coreutils/faq/coreutils-faq.html#Argument-list-too-long ;

la recette 9.2, Traiter les noms de fichiers contenant des caractres tranges, page 193.

15.14. Journaliser vers syslog depuis un script


Problme
Vous souhaitez que votre script envoie des messages de journalisation syslog.

Solution
Utilisez logger, Netcat ou les fonctions bash de redirection du rseau.
logger est install par dfaut sur la plupart des systmes et constitue une solution simple
pour envoyer des messages aux services syslog local. En revanche, il ne permet pas de
communiquer avec des htes distants. Pour cela, vous pouvez vous tourner vers bash ou
Netcat.
$ logger -p local0.notice -t $0[$$] message de test

Netcat est appel le couteau suisse de TCP/IP . En gnral, il nest pas install par dfaut. Par ailleurs, son ct outil de piratage peut le voir interdit par certaines politiques
de scurit. Cependant, les fonctions de redirection du rseau disponibles dans bash permettent dobtenir des rsultats trs similaires. Pour plus de dtails sur la partie
<133>$0[$$], consultez les explications de la recette 15.9, page 348.
# Netcat
$ echo "<133>$0[$$]: Test dun message syslog depuis Netcat" | nc -w1 -u
loghost 514

# bash
$ echo "<133>$0[$$]: Test dun message syslog depuis bash" \
> /dev/udp/loghost.exemple.fr/514

Discussion
logger et Netcat disposent dun grand nombre de fonctionnalits, que nous ne pouvons
inclure ici. Consultez leur page de manuel respective.

Voir aussi

man logger ;

man nc ;

la recette 15.9, Utiliser la redirection du rseau de bash, page 348.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

360

Chapitre 15 Scripts labors

15.15. Envoyer un message lectronique depuis


un script
Problme
Vous souhaitez que votre script puisse envoyer des courriers lectroniques, avec ou sans
pices jointes.

Solution
Pour mettre en uvre les solutions proposes, un client de messagerie, comme mail,
mailx ou mailto, et un agent de transfert du courrier (MTA Message Transfer Agent)
doivent tre installs et oprationnels. Dautre part, votre environnement de messagerie doit tre correctement configur. Malheureusement, toutes ces hypothses ne sont
pas toujours satisfaites et les solutions devront tre soigneusement testes dans lenvironnement cible.
La premire manire denvoyer un courrier lectronique depuis un script consiste
crire le code qui gnre et envoie le message :
# Simple.
cat corps_message | mail -s "Objet du message" dest1@exemple.fr
dest2@exemple.fr

Ou :
# Pice jointe uniquement.
$ uuencode /chemin/vers/fichier_piece_jointe nom_piece_jointe | mail -s
"Objet du message" dest1@exemple.fr dest2@exemple.fr

Ou :
# Pice jointe et corps.
$ (cat corps_message ; uuencode /chemin/vers/fichier_piece_jointe
nom_piece_jointe) | mail -s "Objet du message" dest1@exemple.fr
dest2@exemple.fr

En pratique, ce nest pas toujours aussi simple. Tout dabord, alors que uuencode sera probablement install, mail et ses amis pourront faire dfaut, ou bien leurs possibilits varieront. Dans certains cas, mail et mailx sont le mme programme, avec des liens
physiques ou symboliques. Dans une utilisation relle, vous souhaiterez mettre en place
une certaine abstraction afin de faciliter la portabilit. Par exemple, mail fonctionne
avec Linux et BSD, mais mailx est obligatoire avec Solaris puisque sa version de mail ne
reconnat pas loption -s. mailx fonctionne avec certaines distributions Linux (par
exemple, Debian), mais pas avec dautres (par exemple, Red Hat). Dans notre code, nous
choisissons le client de messagerie en fonction du nom dhte, mais une commande
uname -o serait prfrable.
# bash Le livre de recettes : exemple_email
# Fixer certains paramtres de messagerie. Utiliser une
# instruction case avec uname ou hostname pour ajuster
# ces paramtres l'environnement.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.15. Envoyer un message lectronique depuis un script

361

case $HOSTNAME in
*.societe.fr
) MAILER='mail'
;; # Linux et BSD.
hote1.*
) MAILER='mailx' ;; # Solaris, BSD et certains Linux.
hote2.*
) MAILER='mailto' ;; # Pratique, si install.
esac
DESTINATAIRES='dest1@exemple.fr dest2@exemple.fr'
OBJET="Donnes de $0"
[...]
# Crer le corps comme un fichier ou une variable avec echo,
# printf ou un here document. Crer ou modifier $OBJET et/ou
# $DESTINATAIRES en fonction des besoins.
[...]
( echo $corps_message ; uuencode $piece_jointe $(basename $piece_jointe) ) \
| $MAILER -s "$OBJET" "$DESTINATAIRES"

Notez que lenvoi de pices jointes dpend galement du client utilis pour lire le message rsultant. Les clients modernes, comme Thunderbird et Outlook, dtecteront un
message uuencod et le prsenteront comme une pice jointe. Ce ne sera peut-tre pas
le cas avec dautres clients. Vous pouvez toujours enregistrer le message et le passer
uudecode (cet outil est suffisamment intelligent pour sauter le corps du message et ne
traiter que la pice jointe), mais ce nest pas aussi convivial.
La deuxime manire denvoyer un courrier lectronique depuis un script consiste externaliser cette tche cron. Bien que les fonctionnalits de cron varient dun systme
lautre, toutes les versions permettent denvoyer par courrier lectronique la sortie
dune tche son propritaire ou lutilisateur dsign par la variable MAILTO. Vous
pouvez donc exploiter ce fonctionnement pour envoyer des messages lectroniques, en
supposant que votre infrastructure de messagerie soit oprationnelle.
La bonne manire dcrire un script excut par cron (et dautant diront pour tout script
ou outil Unix) consiste le rendre silencieux, except lorsquil rencontre un avertissement ou une erreur. Si ncessaire, ajoutez une option -v pour le passer en mode plus
bavard, mais ne lexcutez pas dans ce mode depuis cron, tout au moins aprs avoir termin les tests. En effet, comme nous lavons not, cron envoie par courrier lectronique
lintgralit de la sortie de la tche. Si vous recevez un message de cron chaque fois que
le script sexcute, vous finirez par les ignorer. En revanche, si le script est silencieux, except en cas de problme, vous ne recevrez un avis que dans ce cas.

Discussion
mailto est une version multimdia et compatible MIME de mail. Vous pouvez donc viter lemploi de uuencode pour envoyer des pices jointes, mais il nest pas aussi rpandu
que mail et mailx. En cas de problmes, elm ou mutt peut tre utilis la place de mail,
mailx ou mailto, mais il est peu probable que ces outils soient installs par dfaut. Par
ailleurs, certaines versions de ces programmes acceptent loption -r qui permet de prciser une adresse de retour. mutt dispose galement dune option -a qui facilite lenvoi
de pices jointes.
cat "$corps_message" | mutt -s "$objet" -a "$piece_jointe" "$destinataires"

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

362

Chapitre 15 Scripts labors

Vous pouvez galement vous intresser mpack, mais il est peu probable quil soit install par dfaut. Consultez le dpt de logiciels de votre systme ou bien tlchargez le
code source depuis ftp://ftp.andrew.cmu.edu/pub/mpack/. Voici ce quen dit sa page de manuel :
Le programme mpack encode le fichier nomm en un ou plusieurs messages MIME.
Les messages rsultants sont envoys par courrier lectronique un ou plusieurs destinataires, sont crits dans un fichier nomm ou un ensemble de fichiers, ou bien
sont posts dans diffrents groupes de discussion.

Le chapitre 8 du livre Introduction aux scripts shell de Nelson H.F. Beebe et Arnold Robbins (ditions OReilly) propose une autre manire de grer les noms et les emplacements des clients de messagerie :
# bash Le livre de recettes : exemple_email_iss
# Extrait du chapitre 8 du livre Introduction aux scripts shell.
for MAIL in /bin/mailx /usr/bin/mailx /usr/sbin/mailx /usr/ucb/mailx
/bin/mail /usr/bin/mail; do
[ -x $MAIL ] && break
done
[ -x $MAIL ] || { echo 'Client de messagerie non trouv !' >&2; exit 1; }

uuencode est une ancienne mthode de conversion des donnes binaires en un texte
ASCII avant leur transfert sur des lignes qui ne prennent pas en charge le format binaire, cest--dire Internet avant quil ne devienne lInternet et le Web. Nous savons de source sre que ce type de lignes existe encore. Mme si vous nen rencontrerez jamais, il
nest pas inutile de savoir convertir une pice jointe en un format ASCII que tout client
de messagerie moderne saura reconnatre. Il existe galement les utilitaires uudecode et
mimencode. Sachez que les fichiers uuencods sont 30 % plus volumineux que leurs versions binaires. Vous pouvez donc les compresser avant de les uuencoder.
Le problme du courrier lectronique, mises part les diffrences entre les clients de
messagerie (MUA Mail User Agent) comme mail et mailx, est quil sappuie sur de
nombreux composants cooprant. Ce point a t exacerb par les messages non sollicits car les administrateurs de messagerie ont d svrement verrouiller les serveurs, ce
qui nest pas sans effet sur les scripts. Nous pouvons uniquement vous conseiller de soigneusement tester votre solution et de contacter vos administrateurs systme et de messagerie en cas de besoin.
Vous risquez galement de rencontrer des problmes avec certaines distributions Linux
orientes stations de travail, comme Ubuntu, car elles ninstallent ou nexcutent aucun
agent de transfert de courrier. En effet, elles supposent que vous utiliserez un client graphique complet, comme Evolution ou Thunderbird. Dans ce cas, les clients de messagerie en ligne de commande et lenvoi de courrier partir de cron ne fonctionneront pas.
Consultez le support en ligne de votre distribution pour trouver de laide.

Voir aussi

man mail ;

man mailx ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

15.16. Automatiser un processus plusieurs phases

man mailto ;

man mutt ;

man uuencode ;

man cron ;

man 5 crontab.

363

15.16. Automatiser un processus plusieurs


phases
Problme
Vous souhaitez automatiser une tche ou un processus long, mais il peut ncessiter une
intervention manuelle et vous devez donc tre en mesure de le redmarrer partir de
diffrents points. Vous avez besoin dune instruction de type GOTO, mais elle existe pas
dans bash.

Solution
Utilisez une instruction case pour dcomposer votre script en sections ou phases.
Tout dabord, nous dfinissons une solution standard pour obtenir des rponses de
lutilisateur :
# bash Le livre de recettes : fonc_choisir
function choisir {
# Laisser l'utilisateur faire un choix et retourner une rponse
# normalise. Le traitement de la rponse par dfaut et de la
# suite du processus est du ressort d'une construction if/then
# aprs le choix dans le code principal.
local reponse
printf "%b" "\a"
# Faire retentir la sonnerie.
read -p "$*" reponse
case "$reponse" in
[oO1] ) choix='o';;
[nN0] ) choix='n';;
*
) choix="$reponse";;
esac
} # Fin de la fonction choisir.

Ensuite, nous dfinissons les diffrentes phases :


# bash Le livre de recettes : utiliser_phases
# Boucle principale.
until [ "$phase" = "Fini." ]; do

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

364

Chapitre 15 Scripts labors


case $phase in
phase0 )
CettePhase=0
PhaseSuivante="$(( $CettePhase + 1 ))"
echo '############################################'
echo "Phase$CettePhase = Initialisation de la compilation"
# Initialisations effectues uniquement au dbut d'un
# nouveau cycle de compilation.

# ...
echo "Phase${CettePhase}=Termine"
phase="phase$PhaseSuivante"
;;
# ...
phase20 )
CettePhase=20
PhaseSuivante="$(( $CettePhase + 1 ))"
echo '############################################'
echo "Phase$CettePhase = Traitement principal de la compilation"
# ...
choisir "[P$CettePhase] Stopper et apporter des modifications ? [o/N]
: "
if [ "$choix" = "o" ]; then
echo "Excuter nouveau '$MONNOM phase${CettePhase}' aprs prise
en compte de ce cas."
exit $CettePhase
fi
echo "Phase${CettePhase}=Termine"
phase="phase$PhaseSuivante"
;;
# ...
* )
echo "Un problme ?!? Vous n'auriez jamais d arriver ici !"
echo "Essayez $0 -h"
exit 99
phase="Fini."
;;
esac
printf "%b" "\a"
done

[05/03/08]

bash Le livre de recettes

# Faire retentir la sonnerie.

Elodie FRITSCH <elodie.fritsch@total.com>

15.16. Automatiser un processus plusieurs phases

365

Discussion
Puisque les codes de sortie doivent avoir une valeur infrieure 255, la ligne exit
$CettePhase dtermine le nombre de phases. Dautre part, la ligne exit 99 vous limite
galement un nombre de phases infrieur, mme si celui-ci peut tre facilement ajust. Si vous avez besoin de plus de 254 phases, nous vous souhaitons bon courage. Dans
ce cas, changez le schma dutilisation des codes de sortie ou enchanez plusieurs scripts.
Il serait sans doute bon de dfinir une procdure dutilisation et/ou de rcapitulatif qui
liste les diffrentes phases :
Phase0 = Initialisation de la compilation
...
Phase20 = Traitement principal de la compilation
...
Phase28 ...

Pour cela, vous pouvez obtenir le texte depuis le code laide dune commande comme
grep 'Phase$CettePhase' mon_script.
Si vous souhaitez journaliser le droulement du processus dans un fichier local, vers
syslog ou par tout autre mcanisme, dfinissez une fonction de type logmsg et utilisez-la
dans le code. En voici un exemple simple :
function logmsg {
# Afficher un message dat lcran et dans un fichier de
# journalisation. tee -a permet dajouter les messages.
printf "%b" "`date '+%Y-%m-%d %H:%M:%S'`: $*" | tee -a $JOURNAL
} # Fin de la fonction logmsg.

Vous aurez sans doute remarqu que ce script ne respecte pas notre habitude de rester
silencieux except en cas de problme. Puisque son fonctionnement est interactif, nous
trouvons ce comportement normal.

Voir aussi

la recette 3.5, Lire lentre de lutilisateur, page 64 ;

la recette 3.6, Attendre une rponse Oui ou Non, page 65 ;

la recette 15.14, Journaliser vers syslog depuis un script, page 359.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16
Configurer bash

Aimeriez-vous travailler dans un environnement qui ne puisse tre adapt vos


prfrences ? Imaginez que vous ne puissiez pas ajuster la hauteur de votre chaise ou
que vous soyez oblig demprunter un long chemin pour aller la caftria, simplement
parce quune autre personne a dcid que ctait la meilleure solution . Cette absence de souplesse ne serait pas accepte trs longtemps. Cependant, dans les environnements informatiques, la plupart des utilisateurs sy attendent et lacceptent. Si vous
faites partie de ces personnes qui pensent que linterface utilisateur est fige et non modifiable, vous tes dans lerreur. Linterface nest absolument pas grave dans le marbre.
bash vous permet de la personnaliser afin de simplifier votre travail.
bash apporte un environnement trs puissant et trs souple. Si vous tes un utilisateur
Unix lambda ou si vous tes habitu un environnement moins souple, vous nimaginez sans doute pas toutes les possibilits. Ce chapitre explique comment configurer bash
afin de ladapter vos besoins et vos prfrences. Si vous estimez que le nom de la commande Unix cat est ridicule, vous pouvez dfinir un alias pour le changer. Si vous employez trs frquemment un jeu de commandes rduit, vous pouvez leur attribuer des
abrviations. Vous pouvez mme crer des alias qui correspondent vos erreurs de saisie classiques (par exemple, mroe pour la commande more). Vous avez la possibilit
de crer vos propres commandes, qui peuvent tre utilises de la mme manire que les
commandes Unix standard. Linvite peut tre modifie de manire fournir des informations utiles (par exemple, le rpertoire de travail). Il est mme possible de modifier
le comportement de bash. Par exemple, vous pouvez le rendre insensible la casse afin
quil ne fasse aucune diffrence entre les lettres majuscules et minuscules. Vous allez
tre agrablement surpris par les possibilits damlioration de votre productivit grce
de simples modifications de bash, en particulier de readline.
Pour plus dinformations sur la personnalisation et la configuration de bash, consultez
le chapitre 3 du livre Le shell bash, 3e dition, de Cameron Newham et Bill Rosenblatt
(ditions OReilly).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

368

Chapitre 16 Configurer bash

16.1. Options de dmarrage de bash


Problme
Vous souhaitez comprendre les diffrentes options disponibles au dmarrage de bash,
mais bash --help ne vous est daucune aide.

Solution
Outre bash --help, essayez bash -c "help set" et bash -c help, ou simplement helpset
et help si vous vous trouvez dj dans un shell bash.

Discussion
bash propose parfois plusieurs manires de dfinir la mme option. Vous pouvez fixer
des options au dmarrage (par exemple, bash -x), puis dsactiver ultrieurement la
mme option de manire interactive en utilisant set +x.

Voir aussi

lannexe A, Listes de rfrence, page 505 ;

la recette 19.12, Vrifier la syntaxe dun script bash, page 499.

16.2. Personnaliser linvite


Problme
Par dfaut, linvite de bash est souvent peu informative et simplement constitue dun
caractre $. Vous souhaitez la personnaliser afin quelle affiche des informations utiles.

Solution
Dfinissez les variables $PS1 et $PS2 selon vos souhaits.
Linvite par dfaut varie en fonction des systmes. bash affiche gnralement ses numros de version principaux et secondaires (\s-\v\$), par exemple bash-3.00$. Cependant, votre systme peut dfinir sa propre invite par dfaut, comme [utilisateur@hte
~]$ ([\u@\h \W]\$) pour Fedora Core 5. Notre solution prsente huit invites de base et
trois invites plus fantaisistes.

Invites de base
Voici huit exemples dinvites qui fonctionnent avec bash partir de la version 1.14.7. La
partie \$ finale affiche # lorsque lidentifiant dutilisateur rel vaut zro (le compte de
root) et $ sinon :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.2. Personnaliser linvite

369

1. Nom dutilisateur@nom dhte, date et heure, rpertoire de travail :


$ export PS1='[\u@\h \d \A] \w \$ '
[jp@freebsd mar ao 07 19:32] ~ $ cd /usr/local/bin/
[jp@freebsd mar ao 07 19:32] /usr/local/bin $

2. Nom dutilisateur@nom dhte long, date et heure au format ISO 8601, nom de
base du rpertoire de travail (\W) :
$ export PS1='[\u@\H \D{%Y-%m-%d %H:%M:%S%z}] \W \$ '
[jp@freebsd.jpsdomain.org 2007-08-07 19:33:03+0200] ~ $ cd
/usr/local/bin/
[jp@freebsd.jpsdomain.org 2007-08-07 19:33:03+0200] bin $

3. Nom dutilisateur@nom dhte, version de bash, rpertoire de travail (\w) :


$ export PS1='[\u@\h \V \w] \$ '
[jp@freebsd 3.1.17] ~ $ cd /usr/local/bin/
[jp@freebsd 3.1.17] /usr/local/bin $

4. Saut de ligne, nom dutilisateur@nom dhte, PTY de base, niveau de shell,


numro dhistorique, saut de ligne, rpertoire de travail complet ($PWD) :
$ export PS1='\n[\u@\h \l:$SHLVL:\!]\n$PWD\$ '
[jp@freebsd ttyp0:3:21]
/home/jp$ cd /usr/local/bin/
[jp@freebsd ttyp0:3:22]
/usr/local/bin$

PTY correspond au numro de pseudo-terminal (dans le jargon Linux) auquel vous


tes connect. Lorsque plusieurs sessions sont en cours, il sera utile pour vous reprer. Le niveau de shell correspond la profondeur dimbrication des sous-shells.
Lors de la premire ouverture de session, il vaut 1 et sincrmente suite au lancement de processus secondaires (par exemple screen). Ainsi, aprs lexcution de
screen, il doit valoir 2. Le numro dhistorique correspond au numro de la commande en cours dans lhistorique.
5. Nom dutilisateur@nom dhte, code de sortie de la dernire commande, rpertoire de travail. Notez que le code de sortie est rinitialis (et donc inutile) si vous
excutez une commande dans linvite :
$ export PS1='[\u@\h $? \w \$ '
[jp@freebsd 0 ~ $ cd /usr/local/bin/
[jp@freebsd 0 /usr/local/bin $ true
[jp@freebsd 0 /usr/local/bin $ false
[jp@freebsd 1 /usr/local/bin $ true
[jp@freebsd 0 /usr/local/bin $

6. Dans lexemple suivant, nous affichons le nombre de tches en cours dans le shell.
Cette information sera utile si vous avez lanc un grand nombre de tches en
arrire-plan et en avez oubli certaines :
$ export PS1='\n[\u@\h jobs:\j]\n$PWD\$ '
[jp@freebsd jobs:0]

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

370

Chapitre 16 Configurer bash


/tmp$ ls -lar /etc > /dev/null &
[1] 96461
[jp@freebsd jobs:1]
/tmp$
[1]+ Exit 1

ls -lar /etc >/dev/null

[jp@freebsd jobs:0]
/tmp$

7. Soyons fous et affichons toutes les informations disponibles. Nom dutilisateur@nom dhte, tty, niveau, historique, tches, version et rpertoire de travail
complet :
$ export PS1='\n[\u@\h t:\l l:$SHLVL h:\! j:\j v:\V]\n$PWD\$ '
[jp@freebsd t:ttyp1 l:2 h:91 j:0 v:3.00.16]
/home/jp$

8. Vous allez aimer ou dtester linvite suivante. Elle affiche nom dutilisateur@nom
dhte, T pour ptty, L pour le niveau de shell, C pour le numro de commande et la
date/heure au format ISO 8601 :
$ export PS1='\n[\u@\h:T\l:L$SHLVL:C\!:\D{%Y-%m-%d_%H:%M:%S_%Z}]\n$PWD\$
'
[jp@freebsd:Tttyp1:L1:C337:2007-08-07_12:06:31_CEST]
/home/jp$ cd /usr/local/bin/
[jp@freebsd:Tttyp1:L1:C338:2007-08-07_12:06:16_CEST]
/usr/local/bin$

Cette invite montre trs clairement qui a fait quoi, quand et o. Elle est parfaitement adapte la documentation des tapes dune tche, par simple copier-coller.
En revanche, certains la trouveront trop lourde et confuse.

Invites fantaisistes
Voici trois invites fantaisistes qui utilisent les squences dchappement ANSI pour
changer les couleurs ou fixer la barre de titre dans une fentre xterm. Sachez cependant
quelles ne fonctionneront pas toujours. Il existe un nombre ahurissant de variables
pour les paramtres systme, lmulation xterm et les clients SSH et telnet, qui affecteront toutes ces invites.
Les squences dchappement doivent tre entoures par \[ et \] pour indiquer bash
que les caractres inclus ne sont pas imprimables. Dans le cas contraire, bash ne grera
pas correctement la longueur des lignes et les coupera au mauvais endroit.
1. Nom dutilisateur@nom dhte, rpertoire de travail en bleu clair (couleur non
visible dans ce livre) :
$ export PS1='\[\033[1;34m\][\u@\h:\w]\$\[\033[0m\] '
[jp@freebsd:~]$
[jp@freebsd:~]$ cd /tmp
[jp@freebsd:/tmp]$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.2. Personnaliser linvite

371

2. Nom dutilisateur@nom dhte, rpertoire de travail dans la barre de titre de la


fentre xterm et dans linvite. Si vous nutilisez pas xterm, linvite risque dafficher
du charabia :
$ export PS1='\[\033]0;\u@\h:\w\007\][\u@\h:\w]\$ '
[jp@ubuntu:~]$
[jp@ubuntu:~]$ cd /tmp
[jp@ubuntu:/tmp]$

3. En couleurs et dans xterm :


$ export
PS1='\[\033]0;\u@\h:\w\007\]\[\033[1;34m\][\u@\h:\w]\$\[\033[0m\] '
[jp@ubuntu:~]$
[jp@ubuntu:~]$ cd /tmp
[jp@ubuntu:/tmp]$

Pour vous viter de saisir toutes ces lignes, les invites prcdentes se trouvent dans le fichier ./ch16/invites disponible dans larchive en tlchargement sur la page http://www.
oreilly.fr/catalogue/2841774473 :
# bash Le livre de recettes : invites
# Nom d'utilisateur@nom d'hte court, date et heure,
# rpertoire de travail (CWD) :
export PS1='[\u@\h \d \A] \w \$ '

# Nom d'utilisateur@nom d'hte long, date et heure au


# format ISO 8601, base du rpertoire de travail (\W) :
export PS1='[\u@\H \D{%Y-%m-%d %H:%M:%S%z}] \W \$ '

# Nom d'utilisateur@nom d'hte court, version de bash,


# rpertoire de travail (\w) :
export PS1='[\u@\h \V \w] \$ '

# Saut de ligne, nom d'utilisateur@nom d'hte, PTY de base,


# niveau de shell, numro d'historique, saut de ligne,
# rpertoire de travail complet ($PWD) :
export PS1='\n[\u@\h \l:$SHLVL:\!]\n$PWD\$ '

# Nom d'utilisateur@nom d'hte court, code de sortie de la


# dernire commande, rpertoire de travail :
export PS1='[\u@\h $? \w \$ '

# Nombre de tches en arrire-plan :


export PS1='\n[\u@\h jobs:\j]\n$PWD\$ '

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

372

Chapitre 16 Configurer bash

# Nom d'utilisateur@nom d'hte court, tty, niveau, historique,


# tches, version, rpertoire de travail complet :
export PS1='\n[\u@\h t:\l l:$SHLVL h:\! j:\j v:\V]\n$PWD\$ '

# Nom d'utilisateur@nom d'hte, T pour ptty, L pour niveau de shell,


# C numro de commande, date et heure au format ISO 8601 :
export PS1='\n[\u@\h:T\l:L$SHLVL:C\!:\D{%Y-%m-%d_%H:%M:%S_%Z}]\n$PWD\$ '

# Nom d'utilisateur@nom d'hte court, rpertoire de travail


# en bleu clair :
export PS1='\[\033[1;34m\][\u@\h:\w]\$\[\033[0m\] '

# Nom d'utilisateur@nom d'hte court, rpertoire de travail dans


# la barre de titre du xterm et dans l'invite :
export PS1='\[\033]0;\u@\h:\w\007\][\u@\h:\w]\$ '

# En couleurs et dans xterm :


export PS1='\[\033]0;\u@\h:\w\007\]\[\033[1;34m\][\u@\h:\w]\$\[\033[0m\] '

Discussion
Notez quune seule invocation de la commande export suffit pour indiquer quune variable doit tre exporte dans les processus enfants.
En supposant que loption promptvars du shell soit active, ce qui est le cas par dfaut,
les chanes dinvite sont dcodes, dveloppes par expansion des paramtres, substitution de commandes et expansion arithmtique, libres des apostrophes et enfin affiches. Les variables dinvite sont $PS1, $PS2, $PS3 et $PS4. Linvite de commande est
$PS1. La variable $PS2 correspond linvite secondaire affiche lorsque bash a besoin
dinformations supplmentaires pour complter une commande. Par dfaut, elle a la
valeur >, mais vous pouvez la redfinir. $PS3 est linvite de linstruction select (voir les
recettes 16.16, page 400, et 16.17, page 406), qui vaut par dfaut #? . Enfin, $PS4 est
linvite de xtrace (dbogage), avec la valeur par dfaut + . Le premier caractre de
$PS4 est rpt autant de fois que ncessaire pour reprsenter le niveau dindirection
dans la commande en cours dexcution :
$ export PS2='Secondaire> '
$ for i in *
Secondaire> do
Secondaire> echo $i
Secondaire> done
app_nulle
fichier_donnees
dur_a_tuer
mcd
mode
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.2. Personnaliser linvite

373

$ export PS3='Faites votre choix : '


$ select item in 'un deux trois'; do echo $item; done
1) un deux trois
Faites votre choix : ^C

$ export PS4='+ debogage> '


$ set -x
$ echo $( echo $( for i in *; do echo $i; done ) )
+++ debogage> for i in '*'
+++ debogage> echo app_nulle
+++ debogage> for i in '*'
+++ debogage> echo fichier_donnees
+++ debogage> for i in '*'
+++ debogage> echo dur_a_tuer
+++ debogage> for i in '*'
+++ debogage> echo mcd
+++ debogage> for i in '*'
+++ debogage> echo mode
++ debogage> echo app_nulle fichier_donnees dur_a_tuer mcd mode
+ debogage> echo app_nulle fichier_donnees dur_a_tuer mcd mode
app_nulle fichier_donnees dur_a_tuer mcd mode

Puisque linvite nest utile que si bash est employ en mode interactif, il est prfrable
de la dfinir globalement dans /etc/bashrc ou localement dans ~/.bashrc.
Nous vous conseillons de placer une espace en dernier caractre de la chane $PS1. En
sparant ainsi la chane dinvite de la commande saisie, la lecture du contenu de lcran
est plus facile. Pour cette raison et puisque votre chane peut contenir dautres espaces
ou caractres spciaux, il est prfrable dutiliser des guillemets ou mme des apostrophes pour affecter la chane $PS1.
Il existe au moins trois manires dafficher le rpertoire de travail dans linvite : \w, \W
et $PWD. \W affiche le nom de base ou la dernire partie du rpertoire, tandis que \w laffiche en intgralit. Dans les deux cas, ~ remplace la valeur de $HOME (votre rpertoire
personnel). Certains naiment pas ce format et utilisent $PWD pour afficher le rpertoire
de travail complet. Dans ce cas, linvite peut devenir longue et mme tre coupe lorsque larborescence de rpertoires est profonde. Ce problme nerve certains utilisateurs. Voici une fonction qui tronque le chemin :
# bash Le livre de recettes : fonc_tronquer_PWD
function tronquer_PWD {
# Code qui tronque $PWD, adapt du Bash Prompt HOWTO:
# 11.10. Controlling the Size and Appearance of $PWD.
# http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x783.html
# Nombre de caractres de $PWD conserver.
local pwd_longueurmax=30

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

374

Chapitre 16 Configurer bash


# Indicateur de troncation :
local symbole_tronc='...'
# Variable temporaire pour PWD.
local monPWD=$PWD
# Remplacer par '~' la partie initiale de $PWD qui correspond $HOME.
# Facultatif. Mettre en commentaires pour conserver le chemin complet.
monPWD=${PWD/$HOME/~}
if [ ${#monPWD} -gt $pwd_longueurmax ]; then
local pwd_decalage=$(( ${#monPWD} - $pwd_longueurmax ))
echo "${symbole_tronc}${monPWD:$pwd_decalage:$pwd_longueurmax}"
else
echo "$monPWD"
fi

Et sa dmonstration :
$ source tronquer_PWD
[jp@freebsd ttyp0:3:60]
~/voici/un ensemble/de repertoires/vraiment/tres/tres/long/je repete/tres
tres/long$ export PS1='\n[\u@\h \l:$SHLVL:\!]\n$(tronquer_PWD)\$ '
[jp@freebsd ttyp0:3:61]
.../long/je repete/tres tres/long$

Vous remarquerez que les invites prcdentes utilisent les apostrophes afin que $ et les
autres caractres spciaux soient pris littralement. La chane dinvite est value au moment de laffichage et les variables sont donc dveloppes comme attendu. Les guillemets peuvent galement tre employs, mais vous devez alors chapper les mtacaractres du shell, par exemple en utilisant \$ la place de $.
Le numro de commande et le numro dhistorique sont gnralement diffrents. Le
numro dhistorique dune commande reprsente sa position dans lhistorique, qui
peut inclure des commandes qui en sont extraites. Le numro de commande reprsente
sa position dans la suite des commandes excutes pendant la session du shell en cours.
Il existe galement une variable spciale, $PROMPT_COMMAND, qui contient la commande
excuter avant lvaluation et laffichage de $PS1. Son inconvnient, ainsi que celui de
la substitution de commandes dans $PS1, rside dans le fait que les commandes sont excutes chaque affichage de linvite, cest--dire trs souvent. Par exemple, votre invite
peut inclure une substitution de commandes comme $(ls -1 | wc -l) afin de prsenter
le nombre de fichiers du rpertoire de travail. Mais, sur un systme ancien ou trs charg, un rpertoire contenant de nombreux fichiers risque de provoquer des dlais importants avant laffichage de linvite et lopportunit de saisir une commande. Il est
prfrable que les invites restent courtes et simples (nonobstant certains monstres dcrits dans la section Solution). Dfinissez des fonctions ou des alias pour obtenir des informations la demande au lieu dencombrer et de ralentir votre invite.
Pour viter que les chappements ANSI ou xterm non reconnus ne se transforment en
charabia dans votre invite, ajoutez un code similaire au suivant dans votre fichier rc :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.2. Personnaliser linvite

375

case $TERM in
xterm*) export
PS1='\[\033]0;\u@\h:\w\007\]\[\033[1;34m\][\u@\h:\w]\$\[\033[0m\] ' ;;
*) export PS1='[\u@\h:\w]\$ ' ;;
esac

Pour plus dinformations, consultez la section Personnaliser les chanes dinvite, page 507.

Couleurs
Dans lexemple ANSI propos, 1;34m signifie fixer lattribut de caractre clair et la
couleur du caractre bleu . 0m signifie effacer tous les attributs et nappliquer aucune couleur . La section Squences dchappement ANSI pour la couleur, page 508, explique tous ces codes. Le caractre m final indique une squence dchappement de couleur.
Voici un script qui affiche toutes les combinaisons possibles. Sil naffiche aucune couleur sur votre terminal, cela signifie que les chappements ANSI pour la couleur ne
sont pas activs ou pris en charge.
#!/usr/bin/env bash
# bash Le livre de recettes : couleurs
#
# Script des couleurs ANSI de Daniel Crisman extrait de
# The Bash Prompt HOWTO: 6.1. Colours.
# http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html.
#
# Ce fichier envoie des codes de couleur au terminal afin
# de montrer les possibilits. Chaque ligne correspond au
# code dune couleur de premier plan, parmi 17 (celle par
# dfaut + 16 chappements), suivi dun exemple dutilisation
# sur les neuf couleurs darrire-plan (celle par dfaut +
# 8 chappements).
#
T='gYw' # Le texte de test.
echo -e "\n
44m
45m

40m
41m
46m
47m";

42m

43m\

for FGs in '


m' ' 1m' ' 30m' '1;30m' ' 31m' '1;31m' ' 32m' \
'1;32m' ' 33m' '1;33m' ' 34m' '1;34m' ' 35m' '1;35m' \
' 36m' '1;36m' ' 37m' '1;37m';
do FG=${FGs// /}
echo -en " $FGs \033[$FG $T "
for BG in 40m 41m 42m 43m 44m 45m 46m 47m;
do echo -en "$EINS \033[$FG\033[$BG $T \033[0m";
done
echo;
done
echo

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

376

Chapitre 16 Configurer bash

Voir aussi

le manuel de rfrence de bash ;

./examples/scripts.noah/prompt.bash dans larchive des sources de bash ;

http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/index.html ;

http://sourceforge.net/projects/bashish ;

la recette 1.1, Comprendre linvite de commandes, page 4 ;

la recette 3.7, Choisir dans une liste doptions, page 68 ;

la recette 16.10, Utiliser les invites secondaires : $PS2, $PS3 et $PS4, page 390 ;

la recette 16.16, tendre bash avec des commandes internes chargeables, page 400 ;

la recette 16.17, Amliorer la compltion programmable, page 406 ;

la recette 16.18, Utiliser correctement les fichiers dinitialisation, page 411 ;

la recette 16.19, Crer des fichiers dinitialisation autonomes et portables, page 414 ;

la recette 16.20, Commencer une configuration personnalise, page 416 ;

la section Personnaliser les chanes dinvite, page 507 ;

la section Squences dchappement ANSI pour la couleur, page 508.

16.3. Modifier dfinitivement $PATH


Problme
Vous souhaitez modifier de manire permanente votre chemin.

Solution
Pour commencer, vous devez dterminer o le chemin est dfini, puis le mettre jour.
Pour votre compte local, cette opration se fait probablement dans ~/.profile ou
~/.bash_profile. Trouvez le fichier avec grep -l PATH ~/.[^.]* et modifiez-le laide de
votre diteur prfr. Ensuite chargez le fichier avec source pour que les modifications
prennent effet immdiatement.
Si vous tes root et si vous devez fixer le chemin pour lintgralit du systme, la procdure de base reste identique, mais le rpertoire /etc contient plusieurs fichiers qui peuvent dfinir $PATH, selon votre systme dexploitation et sa version. Le fichier le plus
probable est /etc/profile, mais /etc/bashrc, /etc/rc, /etc/default/login, ~/.ssh/environment et les
fichiers PAM /etc/environment sont galement examiner.

Discussion
La commande grep -l PATH ~/.[^.]* prsente deux aspects intressants : lexpansion
des caractres gnriques du shell et la prsence des rpertoires /. et /... Pour plus de dtails, consultez la recette 1.5, page 10.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.4. Modifier temporairement $PATH

377

Les emplacements indiqus dans $PATH ont un impact sur la scurit, en particulier
lorsque vous tes root. Si un rpertoire modifiable par tout le monde se trouve dans le
chemin de root avant les rpertoires classiques (cest--dire, /bin, /sbin), un utilisateur local peut alors crer des fichiers que root risque dexcuter. Des actions indsirables sont
alors possibles sur le systme. Cest pourquoi le rpertoire de travail (.) ne doit jamais
se trouver dans le chemin de root.
Pour tenir compte de ce problme et lviter, vous devez :

dfinir un chemin de root aussi court que possible et ne jamais employer de chemins relatifs ;

bannir les rpertoires modifiables par tout le monde dans le chemin de root ;

envisager des chemins explicites dans les scripts shell excuts par root ;

envisager de figer des chemins absolus vers les utilitaires employs dans les scripts
shell excuts par root ;

placer en derniers les rpertoires des utilisateurs ou des application dans $PATH et
uniquement pour les utilisateurs sans privilges.

Voir aussi

la recette 1.5, Afficher tous les fichiers cachs, page 10 ;

la recette 4.1, Lancer nimporte quel excutable, page 71 ;

la recette 14.3, Dfinir une variable $PATH sre, page 294 ;

la recette 14.9, Trouver les rpertoires modifiables mentionns dans $PATH, page 300 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303 ;

la recette 16.4, Modifier temporairement $PATH, page 377.

16.4. Modifier temporairement $PATH


Problme
Vous souhaitez ajouter ou retirer facilement un rpertoire la variable $PATH, uniquement pendant la session en cours.

Solution
Il existe plusieurs manires de traiter ce problme.
Vous pouvez ajouter le nouveau rpertoire au dbut ou la fin de la liste, en utilisant
les commandes PATH="nouv_rp:$PATH" ou PATH="$PATH:nouv_rp". Vous devez cependant vrifier que le rpertoire ne se trouve pas dj dans $PATH.
Si vous devez intervenir au milieu du chemin, affichez celui-ci lcran avec echo, puis
servez-vous de la fonction copier-coller pour le dupliquer sur une nouvelle ligne et le
modifier. Vous pouvez galement ajouter les macros bien utiles pour linteraction
avec le shell donnes dans la documentation de readline http://tiswww.tis.case.edu/
php/chet/readline/readline.html#SEC12 :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

378

Chapitre 16 Configurer bash

# Modifier le chemin.
"\C-xp": "PATH=${PATH}\e\C-e\C-a\ef\C-f"
# [...]
# Modifier une variable sur la ligne en cours.
"\M-\C-v": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y="

Ensuite, un appui sur Ctrl-X P affiche le contenu de $PATH sur la ligne en cours afin que
vous puissiez le modifier, tandis que la saisie dun nom de variable et lappui sur Meta
Ctrl-V affiche cette variable en vue de sa modification. Ces deux macros savrent plutt
pratiques.
Pour les cas simples, servez-vous de la fonction suivante (adapte du fichier /etc/profile
de Red Hat Linux) :
# bash Le livre de recettes : fonc_transformer_chemin
# Adapte de Red Hat Linux.
function transformer_chemin {
if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then
if [ "$2" = "apres" ] ; then
PATH="$PATH:$1"
else
PATH="$1:$PATH"
fi
fi
}

Le motif de egrep recherche la valeur de $1 entre deux : ou (|) au dbut (^) ou la fin
($) de la chane dans $PATH. Nous avons opt pour une instruction case dans notre fonction et forc le mme comportement pour un caractre : initial ou final. Notre version
est galement une bonne illustration du fonctionnement de la commande if avec les
codes de sortie. Le premier if utilise le code de sortie fix par grep, tandis que le second
exige lemploi de loprateur de test ([ ]).
Pour les cas plus complexes, et lorsque vous souhaitez grer les erreurs, chargez et utilisez les fonctions gnriques suivantes :
# bash Le livre de recettes : fonc_ajuster_chemin
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Ajouter un rpertoire au dbut ou la fin du chemin, s'il ne s'y trouve
# pas dj. Ne tient pas compte des liens symboliques !
# Retour : 1 ou fixe le nouveau $PATH
# Usage : ajouter_au_chemin <rpertoire> (debut|fin)
function ajouter_au_chemin {
local emplacement=$1
local repertoire=$2
# Vrifier que l'invocation est correcte.
if [ -z "$emplacement" -o -z "$repertoire" ]; then
echo "$0:$FUNCNAME : veuillez prciser un emplacement et un
rpertoire" >&2

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.4. Modifier temporairement $PATH

379

echo "exemple : ajouter_au_chemin debut /bin" >&2


return 1
fi
# Vrifier que le rpertoire n'est pas relatif.
if [ $(echo $repertoire | grep '^/') ]; then
: echo "$0:$FUNCNAME : '$repertoire' est absolu" >&2
else
echo "$0:$FUNCNAME : impossible d'ajouter le rpertoire relatif
'$repertoire' \$PATH" >&2
return 1
fi
# Vrifier que le rpertoire ajouter existe.
if [ -d "$repertoire" ]; then
: echo "$0:$FUNCNAME : le rpertoire existe" >&2
else
echo "$0:$FUNCNAME : '$repertoire' n'existe pas - arrt" >&2
return 1
fi
# Vrifier qu'il n'est pas dj dans le chemin.
if [ $(contient "$PATH" "$repertoire") ]; then
echo "$0:$FUNCNAME : '$repertoire' dj prsente dans \$PATH - arrt"
>&2
else
: echo "$0:$FUNCNAME : ajout du rpertoire \$PATH" >&2
fi
# Dterminer l'opration effectuer.
case $emplacement in
debut* ) PATH="$repertoire:$PATH" ;;
fin* ) PATH="$PATH:$repertoire" ;;
*
) PATH="$PATH:$repertoire" ;;
esac
# Nettoyer le nouveau chemin, puis le fixer.
PATH=$(nettoyer_chemin $PATH)
} # Fin de la fonction ajouter_au_chemin.

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Supprimer un rpertoire du chemin, s'il s'y trouve.
# Retour : fixe le nouveau $PATH
# Usage : retirer_du_chemin <rpertoire>
function retirer_du_chemin {
local repertoire=$1
# Supprimer de $PATH toutes les instances de $repertoire.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

380

Chapitre 16 Configurer bash


PATH=${PATH//$repertoire/}
# Nettoyer le nouveau chemin, puis le fixer.
PATH=$(nettoyer_chemin $PATH)

} # Fin de la fonction retirer_du_chemin.

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Supprimer les caractres ':' de dbut/de fin ou dupliqus, retirer les
# entres en double.
# Retour : affiche le chemin "nettoy"
# Usage : chemin_nettoye=$(nettoyer_chemin $PATH)
function nettoyer_chemin {
local chemin=$1
local nouveau_chemin
local repertoire
# Vrifier que l'invocation est correcte.
[ -z "$chemin" ] && return 1
# Supprimer les rpertoires en double, si prsents.
for repertoire in ${chemin//:/ }; do
contient "$nouveau_chemin" "$repertoire" &&
nouveau_chemin="${nouveau_chemin}:${repertoire}"
done
# Retirer les sparateurs ':' initiaux.
# Retirer les sparateurs ':' finaux.
# Retirer les sparateurs ':' dupliqus.
nouveau_chemin=$(echo $nouveau_chemin | sed 's/^:*//; s/:*$//;
s/::/:/g')
# Retourner le nouveau chemin.
echo $nouveau_chemin
} # Fin de la fonction nettoyer_chemin.

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Dterminer si le chemin contient le rpertoire indiqu.
# Retour : 1 si la cible est contenue dans le motif, 0 sinon
# Usage : contient $PATH $rep
function contient {
local motif=":$1:"
local cible=$2
# La comparaison est sensible la casse, sauf si nocasematch
# est positionn.
case $motif in

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.4. Modifier temporairement $PATH

381

*:$cible:* ) return 1;;


*
) return 0;;
esac
} # Fin de la fonction contient.

Voici quelques exemples dutilisation :


$ source fonc_ajuster_chemin
$ echo $PATH
/bin:/usr/bin:/usr/local/bin:/usr/bin/X11:/usr/X11R6/bin:/home/jp/bin
$ ajouter_au_chemin debut foo
-bash:ajouter_au_chemin : impossible d'ajouter le rpertoire relatif 'foo'
$PATH
$ ajouter_au_chemin fin ~/foo
-bash:ajouter_au_chemin : '/home/jp/foo' nexiste pas - arrt
$ ajouter_au_chemin fin '~/foo'
-bash:ajouter_au_chemin : impossible d'ajouter le rpertoire relatif '~/foo'
$PATH
$ retirer_du_chemin /home/jp/bin
$ echo $PATH
/bin:/usr/bin:/usr/local/bin:/usr/bin/X11:/usr/X11R6/bin
$ ajouter_au_chemin /home/jp/bin
$ ajouter_au_chemin /home/jp/bin
-bash:ajouter_au_chemin : veuillez prciser un emplacement et un rpertoire
exemple : ajouter_au_chemin debut /bin
$ ajouter_au_chemin fin /home/jp/bin
$ echo $PATH
/bin:/usr/bin:/usr/local/bin:/usr/bin/X11:/usr/X11R6/bin:/home/jp/bin
$ retirer_du_chemin /home/jp/bin
$ ajouter_au_chemin debut /home/jp/bin
$ echo $PATH
/home/jp/bin:/bin:/usr/bin:/usr/local/bin:/usr/bin/X11:/usr/X11R6/bin

Discussion
Ce problme et les fonctions du fichier fonc_ajuster_chemin illustrent quatre points intressants.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

382

Chapitre 16 Configurer bash

Premirement, si vous tentez de modifier votre chemin ou nimporte quelle autre variable denvironnement dans un script shell, cela ne fonctionne pas car les scripts sexcutent dans des sous-shells qui disparaissent lorsque le script se termine, en emportant
avec eux les variables modifies. Cest pourquoi nous chargeons les fonctions dans le
shell courant et les invoquons depuis cet environnement.
Deuximement, vous aurez not que ajouter_au_chemin fin ~/foo retourne une erreur de type nexiste pas tandis que ajouter_au_chemin fin '~/foo' retourne une
erreur impossible dajouter un rpertoire relatif . En effet, ~/foo est dvelopp par le
shell en /home/jp/foo avant dtre pass la fonction. Il est assez frquent doublier lexpansion du shell. Pour savoir prcisment ce qui est pass aux scripts et aux fonctions,
utilisez la commande echo.
Troisimement, nous employons des lignes comme "$0:$FUNCNAME : veuillez prciser un rpertoire" >&2. La partie $0:$FUNCNAME permet didentifier lorigine dun
message derreur. $0 reprsente toujours le nom du programme en cours (-bash dans
lexemple de la solution et le nom de votre script ou programme dans les autres cas). En
ajoutant le nom de la fonction, il est plus facile de dterminer la source des problmes
lors du dbogage. La redirection de la commande echo vers >&2 envoie la sortie sur
STDERR, cest--dire l o les informations dexcution destines lutilisateur, en particulier les avertissements et les erreurs, doivent tre affiches.
Quatrimement, vous pourriez regretter que les fonctions prsentent des interfaces incohrentes, puisque ajouter_au_chemin et supprimer_du_chemin fixent la variable
$PATH, tandis que nettoyer_chemin affiche le chemin nettoy et contient retourne vrai
ou faux. Dans une situation relle, nous ne procderions pas de cette faon, mais cet
exemple est ainsi plus intressant et prsente les diffrentes manires de raliser les choses. Nous pourrions galement justifier ces interfaces par les oprations ralises par les
fonctions.

Voir aussi

les fonctions de manipulation de $PATH similaires plus concises, mais moins claires,
dans le fichier ./examples/functions/pathfuncs disponible dans larchive des sources de
toute version rcente de bash ;

la recette 10.5, Utiliser des fonctions : paramtres et valeur de retour, page 213 ;

la recette 14.3, Dfinir une variable $PATH sre, page 294 ;

la recette 14.9, Trouver les rpertoires modifiables mentionns dans $PATH, page 300 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303 ;

la recette 16.3, Modifier dfinitivement $PATH, page 376 ;

la recette 16.20, Commencer une configuration personnalise, page 416 ;

lannexe B, Exemples fournis avec bash, page 559.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.5. Dfinir $CDPATH

383

16.5. Dfinir $CDPATH


Problme
Vous souhaitez pouvoir passer facilement dans quelques rpertoires.

Solution
Fixez la variable $CDPATH de manire adquate. Les rpertoires que vous utilisez le plus
souvent seront probablement peu nombreux. Prenons un exemple forc, en supposant
que vous passez beaucoup de temps travailler dans les rpertoires rc de init :
/home/jp$ cd rc3.d
bash: cd: rc3.d: Aucun fichier ou rpertoire de ce type
/home/jp$ export CDPATH='.:/etc'
/home/jp$ cd rc3.d
/etc/rc3.d
/etc/rc3.d$ cd rc5.d
/etc/rc5.d
/etc/rc5.d$
/etc/rc5.d$ cd games
bash: cd: games: Aucun fichier ou rpertoire de ce type
/etc/rc5.d$ export CDPATH='.:/etc:/usr'
/etc/rc5.d$ cd games
/usr/games
/usr/games$

Discussion
Le manuel de rfrence de bash stipule que $CDPATH est une liste de rpertoires spars
par des deux-points qui joue le rle dun chemin de recherche pour la commande interne cd. Vous pouvez donc la voir comme une variable $PATH rserve cd. Elle est un peu
subtile, mais peut savrer trs pratique.
Si largument de cd commence par une barre oblique, $CDPATH nest pas consulte. Lorsque $CDPATH est utilise, le nom de chemin absolu du nouveau rpertoire est affich sur
STDOUT, comme dans lexemple prcdent.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

384

Chapitre 16 Configurer bash

Faites attention lorsque bash fonctionne en mode POSIX (par exemple,


en tant que /bin/sh ou avec --posix). Le manuel de rfrence de bash
prcise le point suivant :
Si $CDPATH est fixe, la commande interne cd ne lui ajoute pas implicitement le rpertoire de travail. Autrement dit, cd chouera si aucun
nom de rpertoire valide ne peut tre construit partir du contenu de
$CDPATH, mme sil existe un rpertoire du nom indiqu dans le rpertoire de travail.
Pour viter ce problme, ajoutez explicitement . $CDPATH. Cependant, dans ce cas, un autre aspect subtil mentionn dans le manuel de
rfrence de bash intervient :
Si un nom de rpertoire non vide de $CDPATH est utilis ou si - est le
premier argument, et si le changement de rpertoire russit, le nom de
chemin absolu du nouveau rpertoire de travail est affich sur la sortie
standard.
Autrement dit, chaque fois que vous utilisez cd, le nouveau chemin est
affich sur STDOUT. Il ne sagit pas du comportement standard.

Voici les rpertoires qui sont gnralement ajouts $CDPATH :


.
Le rpertoire de travail (voir lavertissement prcdent).
~/
Le rpertoire personnel.
..
Le rpertoire parent.
../..
Le rpertoire parent du parent.
~/.dirlinks
Un rpertoire cach ne contenant que des liens symboliques vers dautres rpertoires frquemment utiliss.
Les suggestions prcdentes donnent donc :
export CDPATH='.:~/:..:../..:~/.dirlinks'

Voir aussi

help cd ;

la recette 16.13, Concevoir une meilleure commande cd, page 396 ;

la recette 16.20, Commencer une configuration personnalise, page 416 ;

la recette 18.1, Naviguer rapidement entre des rpertoires quelconques, page 475.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.6. Raccourcir ou modifier des noms de commandes

385

16.6. Raccourcir ou modifier des noms de


commandes
Problme
Vous souhaitez raccourcir une commande longue ou complexe que vous utilisez frquemment, ou bien vous voulez renommer une commande dont vous oubliez toujours
le nom ou dont la saisie vous semble complique.

Solution
Ne modifiez pas manuellement le nom des fichiers excutables, ni ne les dplacez, car
de nombreuses fonctionnalits dUnix et de Linux sattendent trouver certaines commandes des endroits prcis. la place, vous devez employer des alias, des fonctions ou
des liens symboliques.
Comme le prcise le manuel de rfrence de bash, les alias permettent demployer un
mot la place dune chane lorsquil est utilis comme premier mot dune commande
simple. Le shell gre une liste des alias, qui sont dfinis et retirs laide des commandes
internes alias et unalias . Autrement dit, vous pouvez renommer des commandes, ou
crer une macro, en plaant plusieurs commandes dans un alias. Par exemple, alias
copy='cp' ou alias ll.='ls -ld .*'.
Les alias ne sont dvelopps quune seule fois. Vous pouvez donc modifier le fonctionnement dune commande, comme alias ls='ls -F', sans entrer dans une boucle infinie. Dans la plupart des cas, seul le premier mot de la ligne de commande fait lobjet
dune expansion dalias. Par ailleurs, les alias ne sont quune substitution de texte. Ils ne
peuvent pas recevoir des arguments. Autrement dit, la commande alias='mkdir $1 &&
cd $1' ne fonctionne pas.
Les fonctions sont utilises de deux manires diffrentes. Premirement, elles peuvent
tre charges dans le shell interactif, o elles deviennent, en ralit, des scripts shell toujours disponibles dans la mmoire. Elles sont gnralement petites et trs rapides, car
elles se trouvent dj en mmoire et sont excutes dans le processus en cours et non
dans un sous-shell cr pour loccasion. Deuximement, elles peuvent tre employes
comme des sous-routines dans un script. Les fonctions acceptent des arguments. Par
exemple :
# bash Le livre de recettes : fonc_calculer
# Calculatrice simple en ligne de commande.
function calculer {
# Uniquement avec des entiers ! --> echo La rponse est : $(( $* ))
# En virgule flottante.
awk "BEGIN {print \"La rponse est : \" $* }";
} # Fin de calculer

Pour une utilisation personnelles ou au niveau du systme, il est sans doute prfrable
dutiliser des alias ou des fonctions pour renommer ou adapter des commandes. En revanche, les liens symboliques savrent trs utiles lorsquune commande doit se trouver

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

386

Chapitre 16 Configurer bash

en plusieurs endroits la fois. Par exemple, les systmes Linux utilisent gnralement
/bin/bash, tandis que dautres optent pour /usr/bin/bash, /usr/local/bin/bash ou
/usr/pkg/bin/bash. Mme sil existe une meilleure solution pour rsoudre ce problme
spcifique (en utilisant env, comme lexplique la recette 15.1, page 334), les liens peuvent
souvent tre utiliss. Nous vous dconseillons demployer des liens physiques, car ils
sont plus difficiles reprer si vous ne les recherchez pas explicitement et ils sont plus
faciles rompre par des applications mal crites. Les liens symboliques sont tout simplement plus vidents et plus intuitifs.

Discussion
Habituellement, seul le premier mot dune ligne de commande fait lobjet dune substitution dalias. Cependant, si le dernier caractre dun alias est une espace, le mot suivant est galement examin. En pratique, cela constitue rarement un problme.
Puisque les alias ne peuvent avoir darguments (contrairement leur mise en uvre
dans csh), vous devez employer une fonction sils sont ncessaires. Les alias et les fonctions rsidant en mmoire, il ny a donc pas une grande diffrence.
Lorsque loption expand_aliases du shell nest pas fixe, les alias ne sont pas dvelopps
lorsque le shell nest pas en mode interactif. Lors de lcriture de scripts, il est conseill
de ne pas employer les alias car ils ne seront peut-tre pas prsents sur un autre systme.
Vous devez galement dfinir les fonctions lintrieur du script ou les charger explicitement avant de les utiliser (voir la recette 19.14, page 502). Par consquent, il est prfrable de les dfinir dans votre fichier /etc/bashrc global ou dans votre ~/.bashrc local.

Voir aussi

la recette 10.4, Dfinir des fonctions, page 211 ;

la recette 10.5, Utiliser des fonctions : paramtres et valeur de retour, page 213 ;

la recette 10.7, Redfinir des commandes avec des alias, page 219 ;

la recette 14.4, Effacer tous les alias, page 296 ;

la recette 15.1, Trouver bash de manire portable, page 334 ;

la recette 16.18, Utiliser correctement les fichiers dinitialisation, page 411 ;

la recette 16.19, Crer des fichiers dinitialisation autonomes et portables, page 414 ;

la recette 16.20, Commencer une configuration personnalise, page 416 ;

la recette 19.14, viter les erreurs commande non trouve avec les fonctions, page
502.

16.7. Adapter le comportement et


lenvironnement du shell
Problme
Vous souhaiter adapter lenvironnement de votre shell votre faon de travailler, votre

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.8. Ajuster le comportement de readline en utilisant .inputrc

387

emplacement physique, votre langue ou dautres facteurs.

Solution
Consultez le tableau de la section Ajuster le comportement du shell avec set, shopt et les variables, page 520.

Discussion
Il existe trois manires dajuster diffrents aspects de votre environnement. set est normalise dans POSIX et utilise des options une lettre. shopt est rserve aux options du
shell bash. De nombreuses variables denvironnement existent pour des raisons historiques et pour une compatibilit avec diffrentes applications tierces parties. La manire
dajuster certains comportements peut tre trs confuse. Le tableau A-8, page 521, vous
aidera trouver la bonne solution, mais il est trop long pour tre reproduit ici.

Voir aussi

help set ;

help shopt ;

la documentation de bash (http://www.bashcookbook.com) ;

la section Ajuster le comportement du shell avec set, shopt et les variables, page 520.

16.8. Ajuster le comportement de readline en


utilisant .inputrc
Problme
Vous souhaitez ajuster la gestion de lentre par bash, en particulier la compltion des
commandes. Par exemple, vous la voulez insensible la casse.

Solution
Modifiez ou crez un fichier ~/.inputrc ou /etc/inputrc. Il existe de nombreux paramtres
que vous pouvez ajuster en fonction de vos souhaits. Pour que readline utilise votre fichier lors de son initialisation, fixez la variable $INPUTRC, par exemple set INPUTRC=
'~/.inputrc'. Pour relire le fichier et appliquer ou tester des modifications, invoquez
la commande bind -f nomFichier.
Nous vous conseillons dexaminer la commande bind et la documentation de readline,
en particulier bind -v, bind -l, bind -s et bind -p, mme si cette dernire est assez longue et nigmatique.
Voici quelques configurations pour les utilisateurs dautres environnements, en particulier Windows (voir la section Syntaxe du fichier dinitiation de readline, page 548) :
# bash Le livre de recettes : inputrc

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

388

Chapitre 16 Configurer bash

# configurations/inputrc : paramtres de readline


# Pour le relire (et utiliser les modifications de ce fichier) :
# bind -f $CONFIGURATIONS/inputrc
# Tout d'abord, inclure les liaisons et les affectations de
# variables de niveau systme provenant de /etc/inputrc
# (choue en silence si le fichier n'existe pas).
$include /etc/inputrc
$if Bash
# Ignorer la casse lors de la compltion.
set completion-ignore-case on
# Ajouter une barre oblique aux noms de rpertoires complts.
set mark-directories on
# Ajouter une barre oblique aux noms complts qui sont des liens
# vers des rpertoires.
set mark-symlinked-directories on
# Utiliser ls -F pour la compltion.
set visible-stats on
# Parcourir les compltions ambigus au lieu d'afficher la liste.
"\C-i": menu-complete
# Activer la sonnerie.
set bell-style audible
# Lister les compltions possibles au lieu de faire retentir la
# sonnerie.
set show-all-if-ambiguous on
#
#
#
#

Extrait de la documentation de readline


http://tiswww.tis.case.edu/php/chet/readline/readline.html#SEC12
Les macros sont pratiques pour l'interaction avec le shell.
Modifier le chemi.
"\C-xp": "PATH=${PATH}\e\C-e\C-a\ef\C-f"
# Prparer la saisie d'un mot entre guillemets - insrer des guillemets
# ouvrants et fermants, puis aller juste aprs les guillemets ouvrants.
"\C-x\"": "\"\"\C-b"
# Insrer une barre oblique inverse (test des chappements dans les
# squences et les macros).
"\C-x\\": "\\"
# Mettre entre guillemets le mot courant ou prcdent.
"\C-xq": "\eb\"\ef\""
# Ajouter une liaison pour rafficher la ligne.
"\C-xr": redraw-current-line
# Modifier la variable sur la ligne en cours.
#"\M-\C-v": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y="
"\C-xe": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y="
$endif

Testez ces paramtres, ainsi que dautres. Notez galement lutilisation de la directive
$include pour les paramtres de niveau systme, mais vous pouvez les modifier si vous

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.9. Crer son rpertoire priv dutilitaires

389

le souhaitez. Consultez la recette 16.20, page 416, pour plus dinformations sur le fichier
tlchargeable.

Discussion
Peu dutilisateurs savent que la bibliothque Readline de GNU peut tre personnalise,
sans mentionner sa puissance et sa souplesse. Cela dit, aucune approche ne conviendra
tout le monde. Vous devez laborer une configuration qui rpond vos besoins et vos
habitudes.
Lors du premier appel de readline, cette fonction effectue son initialisation normale, en
particulier la lecture du fichier indiqu par la variable $INPUTRC ou ~/.inputrc si elle nest
pas fixe.

Voir aussi

help bind ;

la documentation de readline http://www.bashcookbook.com ;

la recette 16.19, Crer des fichiers dinitialisation autonomes et portables, page 414 ;

la recette 16.20, Commencer une configuration personnalise, page 416.

16.9. Crer son rpertoire priv dutilitaires


Problme
Vous disposez dun ensemble dutilitaires personnels, mais vous navez pas les autorisations de root et ne pouvez donc pas les placer dans les rpertoires habituels comme /bin
ou /usr/local/bin, ou bien vous avez une autre raison de vouloir les garder spars.

Solution
Crez un rpertoire ~/bin, dans lequel vous placez vos utilitaires, et ajoutez-le votre
chemin :
$ PATH="$PATH:~/bin"

Apportez cette modification dans lun de vos fichiers dinitialisation du shell, comme
~/.bashrc. Certains systmes ajoutent dj $HOME/bin en dernier rpertoire du chemin
pour les comptes dutilisateurs non privilgis.

Discussion
En tant quutilisateur du shell, vous allez certainement crer de nombreux scripts. Il est
peu pratique de les invoquer en prcisant leur nom de chemin complet. En les runissant dans un rpertoire ~/bin, vous pouvez faire en sorte quils ressemblent des programmes Unix standard, tout au moins pour vous.
Pour des raisons de scurit, najoutez pas votre rpertoire bin au dbut du chemin de

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

390

Chapitre 16 Configurer bash

recherche. Lorsquil commence par ~/bin, il est plus facile de remplacer certaines commandes systme. Si cela arrive par mgarde, vous risquez un simple dsagrment. En revanche, cela peut savrer trs dangereux si lobjectif est dtre malveillant.

Voir aussi

la recette 14.9, Trouver les rpertoires modifiables mentionns dans $PATH, page 300 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303 ;

la recette 16.3, Modifier dfinitivement $PATH, page 376 ;

la recette 16.4, Modifier temporairement $PATH, page 377 ;

la recette 16.6, Raccourcir ou modifier des noms de commandes, page 385 ;

la recette 19.4, Nommer un script test , page 489.

16.10. Utiliser les invites secondaires : $PS2,


$PS3 et $PS4
Problme
Vous souhaitez comprendre le rle des invites $PS2, $PS3 et $PS4.

Solution
$PS2 contient la chane dinvite secondaire utilise lorsque vous saisissez interactivement
une commande qui nest pas encore termine. Il sagit gnralement de > , mais vous
pouvez la redfinir. Par exemple :
[jp@freebsd jobs:0]
/home/jp$ export PS2='Secondaire : '
[jp@freebsd jobs:0]
/home/jp$ for i in $(ls)
Secondaire : do
Secondaire : echo $i
Secondaire : done
couleurs
rep2
tronquer_PWD

$PS3 reprsente linvite de select employe par cette instruction pour demander lutilisateur de saisir une valeur. Sa valeur par dfaut, peu intuitive, est #?. Elle doit tre modifie avant dinvoquer la commande select. Par exemple :
[jp@freebsd jobs:0]
/home/jp$ select i in $(ls)
Secondaire : do
Secondaire : echo $i

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.10. Utiliser les invites secondaires : $PS2, $PS3 et $PS4

391

Secondaire : done
1) couleurs
2) rep2
3) tronquer_PWD
#? 1
couleurs
#? ^C
[jp@freebsd jobs:0]
/home/jp$ export PS3='Choisissez le rpertoire afficher : '
[jp@freebsd jobs:0]
/home/jp$ select i in $(ls); do echo $i; done
1) couleurs
2) rep2
3) tronquer_PWD
Choisissez le rpertoire afficher : 2
rep2
Choisissez le rpertoire afficher : ^C

$PS4 est affiche pendant la gnration dune trace. Son premier caractre est utilis
autant de fois que ncessaire pour reprsenter la profondeur dimbrication. Sa valeur
+ . Par exemple :
[jp@freebsd jobs:0]
/home/jp$ cat demo
#!/usr/bin/env bash
set -o xtrace
alice=fille
echo "$alice"
ls -l $(type -path vi)
echo ligne 10
ech0 ligne 11
echo ligne 12
[jp@freebsd jobs:0]
/home/jp$ ./demo
+ alice=fille
+ echo fille
fille
++ type -path vi
+ ls -l /usr/bin/vi
-r-xr-xr-x 6 root wheel 285108 May 8 2005 /usr/bin/vi
+ echo ligne 10
ligne 10
+ ech0 ligne 11
./demo: ligne 11: ech0: command not found
+ echo ligne 12
line 12
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

392

Chapitre 16 Configurer bash

[jp@freebsd jobs:0]
/home/jp$ export PS4='+xtrace $LINENO : '
[jp@freebsd jobs:0]
/home/jp$ ./demo
+xtrace 5 : alice=fille
+xtrace 6 : echo fille
girl
++xtrace 8 : type -path vi
+xtrace 8 : ls -l /usr/bin/vi
-r-xr-xr-x 6 root wheel 285108 May 8 2005 /usr/bin/vi
+xtrace 10 : echo ligne 10
line 10
+xtrace 11 : ech0 ligne 11
./demo: ligne 11: ech0: command not found
+xtrace 12 : echo ligne 12
line 12

Discussion
Linvite $PS4 inclut la variable $LINENO, qui, utilise dans une fonction avec des versions
de bash antrieure la 2.0, retourne le nombre de commandes simples excutes et non
le numro de la ligne en cours dans la fonction. Notez galement lemploi des apostrophes qui repoussent lexpansion de la variable jusquau moment de laffichage.

Voir aussi

la recette 1.1, Comprendre linvite de commandes, page 4 ;

la recette 3.7, Choisir dans une liste doptions, page 68 ;

la recette 6.16, Crer des menus simples, page 142 ;

la recette 6.17, Modifier linvite des menus simples, page 143 ;

la recette 16.2, Personnaliser linvite, page 368 ;

la recette 19.13, Dboguer des scripts, page 500.

16.11. Synchroniser lhistorique du shell entre


des sessions
Problme
Vous utilisez plusieurs sessions bash la fois et vous souhaitez quelles partagent un historique. Vous souhaitez galement empcher que la dernire session ferme crase lhistorique des autres sessions.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.12. Fixer les options de lhistorique du shell

393

Solution
Utilisez la commande history pour synchroniser manuellement ou automatiquement
lhistorique entre des sessions.

Discussion
Avec la configuration par dfaut, le dernier shell qui se termine sans erreur crase le fichier dhistorique. Par consquent, sil nest pas synchronis avec les autres shells
ouverts en mme temps, il remplace leur historique. En utilisant loption du shell dcrite la recette 16.12, page 393, vous pouvez ajouter les commandes au fichier dhistorique au lieu de lcraser, mais il pourrait tre utile de le synchroniser entre les sessions.
Une synchronisation manuelle demande lcriture dun alias qui ajoute lhistorique actuel au fichier, puis relit toutes les nouveauts de ce fichier dans lhistorique du shell en
cours :
$ history -a
$ history -n
# Ou un alias 'history sync'.
alias hs='history -a ; history -n'

Cette approche impose une excution manuelle des commandes dans chaque shell lorsque vous souhaitez synchroniser lhistorique. Pour lautomatiser, servez-vous de la variable $PROMPT_COMMAND :
PROMPT_COMMAND='history -a ; history -n'

La valeur de $PROMPT_COMMAND contient une commande excuter chaque fois que linvite interactive par dfaut $PS1 est affiche. Linconvnient de cette approche est quelle
excute ces commandes chaque fois que $PS1 est affiche. Autrement dit, elles sont invoques trs souvent et votre shell, sur un systme fortement charg ou lent, risque dtre
fortement ralenti, en particulier si lhistorique est long.

Voir aussi

help history ;

la recette 16.12, Fixer les options de lhistorique du shell, page 393.

16.12. Fixer les options de lhistorique du shell


Problme
Vous souhaitez mieux matriser lhistorique de la ligne de commande.

Solution
Fixez les variables $HIST* et les options du shell selon le comportement souhait.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

394

Chapitre 16 Configurer bash

Discussion
La variable $HISTFILESIZE dtermine le nombre de lignes autorises dans $HISTFILE ;
par dfaut 500 lignes. $HISTFILE dsigne le fichier ~/.bash_history, ou ~/.sh_history lorsque bash est en mode POSIX. Il peut tre utile daugmenter la valeur de $HISTFILESIZE ;
si elle nest pas dfinie, la taille de $HISTFILE est illimite. La modification de $HISTFILE
nest probablement pas ncessaire, mais si elle nest pas dfinie ou si le fichier nest pas
modifiable, lhistorique ne sera pas crit sur le disque. La variable $HISTSIZE fixe le
nombre de lignes autorises en mmoire.
$HISTIGNORE et $HISTCONTROL dterminent le contenu de lhistorique. $HISTIGNORE est
plus souple car elle vous permet de prciser des motifs qui slectionnent les lignes de
commandes enregistres dans lhistorique. $HISTCONTROL est plus limite car elle naccepte que les mots-cls suivants (toute autre valeur est ignore) :
ignorespace
Les lignes de commandes qui commencent par une espace ne sont pas places dans
lhistorique.
ignoredups
Les lignes de commandes qui correspondent lentre prcdente de lhistorique
ne sont pas enregistres.
ignoreboth
Ce mot-cl quivaut ignorespace et ignoredups.
erasedups
Toutes les lignes de commandes prcdentes qui correspondent la ligne en cours
sont retires de lhistorique avant quelle y soit ajoute.
Si $HISTCONTROL nest pas dfinie ou si elle ne contient aucun des mots-cls prcdents,
toutes les commandes sont enregistres dans lhistorique et sont soumises au traitement
par $HISTIGNORE. La deuxime ligne et les suivantes dune commande sur plusieurs lignes ne sont pas testes et sont ajoutes lhistorique quelle que soit la valeur de $HISTCONTROL.
(Le contenu des paragraphes prcdents est tir de ldition 2.5b du document The GNU
Bash Reference Manual pour bash Version 2.05b, dernire mise jour du 15 juillet 2002 ;
voir http://www.gnu.org/software/bash/manual/bashref.html.)
bash version 3 a introduit une nouvelle variable trs intressante, nomme $HISTTIMEFORMAT. Lorsquelle est dfinie une valeur non nulle, elle contient une chane de format strftime utilise lors de laffichage ou de lcriture de lhistorique. Si vous ne
disposez pas de bash version 3, mais si votre terminal dispose dun tampon permettant
de revenir aux commandes prcdentes, lajout dune estampille temporelle linvite
peut savrer utile (voir la recette 16.2, page 368). Faites attention, car, par dfaut, bash
najoute pas despace finale aprs le format. Certains systmes, comme Debian, ont corrig ce fonctionnement :
bash-3.00# history
1 ls -la
2 help history
3 help fc

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.12. Fixer les options de lhistorique du shell


4

395

history

# Pas terrible.
bash-3.00# export HISTTIMEFORMAT='%Y-%m-%d_%H:%M:%S'
bash-3.00# history
1 2006-10-25_20:48:04ls -la
2 2006-10-25_20:48:11help history
3 2006-10-25_20:48:14help fc
4 2006-10-25_20:48:18history
5 2006-10-25_20:48:39export HISTTIMEFORMAT='%Y-%m-%d_%H:%M:%S'
6 2006-10-25_20:48:41history
# Mieux.
bash-3.00# HISTTIMEFORMAT='%Y-%m-%d_%H:%M:%S; '
bash-3.00# history
1 2006-10-25_20:48:04;
2 2006-10-25_20:48:11;
3 2006-10-25_20:48:14;
4 2006-10-25_20:48:18;
5 2006-10-25_20:48:39;
6 2006-10-25_20:48:41;
7 2006-10-25_20:48:47;
8 2006-10-25_20:48:48;

ls -la
help history
help fc
history
export HISTTIMEFORMAT='%Y-%m-%d_%H:%M:%S'
history
HISTTIMEFORMAT='%Y-%m-%d_%H:%M:%S; '
history

# Un peu plus complexe.


bash-3.00# HISTTIMEFORMAT=': %Y-%m-%d_%H:%M:%S; '
bash-3.00# history
1 : 2006-10-25_20:48:04;
2 : 2006-10-25_20:48:11;
3 : 2006-10-25_20:48:14;
4 : 2006-10-25_20:48:18;
5 : 2006-10-25_20:48:39;
6 : 2006-10-25_20:48:41;
7 : 2006-10-25_20:48:47;
8 : 2006-10-25_20:48:48;

ls -la
help history
help fc
history
export HISTTIMEFORMAT='%Y-%m-%d_%H:%M:%S'
history
HISTTIMEFORMAT='%Y-%m-%d_%H:%M:%S; '
history

Le dernier exemple utilise la commande interne : avec le mta-caractre ; pour encapsuler lestampille temporelle dans une commande ne fait rien (par exemple, : 200610-25_20:48:48;). Cela vous permet de rutiliser directement une ligne du fichier dhistorique sans avoir analyser la date. Lespace aprs le caractre : est obligatoire.
Il existe galement des options du shell qui configurent le traitement du fichier dhistorique. Lorsque histappend est fixe, le shell ajoute les commandes au fichier dhistorique. Dans le cas contraire, il lcrase. Notez que le fichier est toujours tronqu la valeur
donne par $HISTSIZE. Si cmdhist est positionne, les commandes sur plusieurs lignes
sont enregistres sous forme dune seule ligne, avec des points-virgules aux endroits adquats. Lorsque lithist est fixe, les commandes multi-lignes sont conserves en incluant des sauts de ligne.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

396

Chapitre 16 Configurer bash

Voir aussi

help history ;

help fc ;

la recette 16.2, Personnaliser linvite, page 368 ;

la recette 16.7, Adapter le comportement et lenvironnement du shell, page 386 ;

la recette 16.11, Synchroniser lhistorique du shell entre des sessions, page 392.

16.13. Concevoir une meilleure commande cd


Problme
Vous employez cd pour aller dans de nombreux rpertoires imbriqus et souhaitez entrer cd ..... la place de cd ../../../.. pour remonter de quatre niveaux.

Solution
Utilisez la fonction suivante :
# bash Le livre de recettes : fonc_cd
# Autoriser l'emploi de 'cd ...' pour remonter de 2 niveaux,
# 'cd ....' pour remonter de 3 niveaux, etc. (comme 4NT/4DOS).
# Usage : cd ..., etc.
function cd {
local option= longueur= compte= chemin_cd= i= # Porte locale et init.
# Si l'option -L ou -P de lien symbolique est prsente, la
# mmoriser, puis la retirer de la lise.
if [ "$1" = "-P" -o "$1" = "-L" ]; then
option="$1"
shift
fi
# La syntaxe spciale est-elle utilise ? Vrifier que $1 n'est pas
# vide, puis examiner les 3 premiers caractres de $1 pour voir s'il
# s'agit de '...' et vrifier s'il n'y a pas de barre oblique en
# tentant une substitution ; si elle choue, il n'y en a pas. Ces
# deux oprations exigent bash 2.0+
if [ -n "$1" -a "${1:0:3}" = '...' -a "$1" = "${1%/*}" ]; then
# La syntaxe spciale est utilise.
longueur=${#1} # Supposer que $1 contient uniquement des points
# et les compter.
compte=2
# 'cd ..' signifie toujours remonter d'un niveau,
# donc ignorer les deux premiers.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.13. Concevoir une meilleure commande cd

397

# Tant qu'il reste des points, remonter d'un niveau.


for ((i=$compte;i<=$longueur;i++)); do
chemin_cd="${chemin_cd}../" # Construire le chemin de cd.
done
# Effectuer le changement de rpertoire.
builtin cd $option "$chemin_cd"
elif [ -n "$1" ]; then
# La syntaxe spciale n'est pas utilise ; invoquer la commande
# cd normale.
builtin cd $option "$*"
else
# La syntaxe spciale n'est pas utilise ; invoquer la commande
# cd normale vers le rpertoire personnel.
builtin cd $option
fi
} # Fin de cd.

Discussion
La commande cd prend les arguments facultatifs -L et -P qui suivent, respectivement,
les liens symboliques et la structure physique des rpertoires. Lorsque lun des deux est
indiqu, nous devons en tenir compte dans le nouveau fonctionnement de cd.
Nous vrifions que $1 nest pas vide et examinons ses trois premiers caractres pour voir
sil sagit de ... . Nous vrifions ensuite labsence dune barre oblique en essayant
une substitution ; si elle choue, il ny a pas de barre oblique. Ces deux oprations de
manipulation de chane ncessitent bash version 2.0+. Une fois cela fait, nous construisons la commande cd relle partir dune boucle for portable. Enfin, nous utilisons
builtin pour invoquer la commande cd du shell et ne pas crer une boucle infinie en appelant rcursivement notre fonction cd. Nous passons galement largument -L ou -P
potentiel.

Voir aussi

help cd ;

http://jpsoft.com pour le shell 4NT, duquel a t tire cette ide ;

la recette 15.5, crire des boucles portables, page 340 ;

la recette 16.5, Dfinir $CDPATH, page 383 ;

la recette 16.14, Crer un nouveau rpertoire et y aller avec une seule commande, page
398 ;

la recette 16.15, Aller au fond des choses, page 399 ;

la recette 16.20, Commencer une configuration personnalise, page 416 ;

la recette 18.1, Naviguer rapidement entre des rpertoires quelconques, page 475.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

398

Chapitre 16 Configurer bash

16.14. Crer un nouveau rpertoire et y aller


avec une seule commande
Problme
Il arrive frquemment de crer de nouveaux rpertoires et dy aller immdiatement
pour effectuer des oprations. Toute cette saisie est fastidieuse.

Solution
Ajoutez la fonction suivante au fichier de configuration adquat, comme ~/.bashrc, et
chargez-la :
# bash Le livre de recettes : fonc_mcd
# Crer un nouveau rpertoire (mkdir) et y aller (cd).
# Usage : mcd (<mode>) <rp>
function mcd {
local nouv_rep='_echec_de_mcd_'
if [ -d "$1" ]; then
# Le rpertoire existe, l'indiquer...
echo "$1 existe dj..."
nouv_rep="$1"
else
if [ -n "$2" ]; then
# Un mode a t indiqu.
command mkdir -p -m $1 "$2" && nouv_rep="$2"
else
# mkdir normal.
command mkdir -p "$1" && nouv_rep="$1"
fi
fi
builtin cd "$nouv_rep"
# Quel qu'il soit, aller dans
# le rpertoire.
} # Fin de mcd.

Par exemple :
$ source fonc_mcd
$ pwd
/home/jp
$ mcd 0700 junk
$ pwd
/home/jp/junk
$ ls -ld .
drwx------ 2 jp jp 4096 2007-08-07 15:55 .

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.15. Aller au fond des choses

399

Discussion
Cette fonction permet dindiquer un mode pour la commande mkdir utilise lors de la
cration du rpertoire. Si le rpertoire existe dj, ce fait est indiqu mais la commande
cd est toujours invoque. Nous utilisons command pour tre certain dignorer toute
fonction shell qui se nommerait mkdir et builtin pour bien utiliser la commande cd du
shell.
Nous affectons galement _echec_de_mcd_ une variable locale dans le cas o mkdir
choue. Si elle russit, le nouveau rpertoire indiqu est attribu. Si elle choue, lexcution de cd affiche un message raisonnablement utile, en supposant que vous utilisiez
peu de rpertoires _echec_de_mcd_ :
$ mcd /etc/junk
mkdir: ne peut crer le rpertoire '/etc/junk': Permission non accorde
-bash: cd: _echec_de_mcd_: Aucun fichier ou rpertoire de ce type

Vous pensez sans doute quil est possible damliorer ce fonctionnement en utilisant
break ou exit lorsque mkdir choue. Vous oubliez que break fonctionne uniquement
dans une boucle for, while ou until et que exit quitte le shell en cours, puisquune
fonction charge avec source sexcute dans le mme processus que le shell. Vous pouvez
cependant utiliser return, mais nous vous laissons cet exercice.
command mkdir -p "$1" && nouv_rep="$1" || exit 1 # Quitte le shell.
command mkdir -p "$1" && nouv_rep="$1" || break
# Ne fonctionne pas.

Vous pourriez galement dfinir la fonction triviale suivante, mais nous prfrons la
version plus robuste donne dans la solution :
function mcd { mkdir "$1" && cd "$1"; }

Voir aussi

man mkdir ;

help cd ;

help function ;

la recette 16.13, Concevoir une meilleure commande cd, page 396 ;

la recette 16.18, Utiliser correctement les fichiers dinitialisation, page 411 ;

la recette 16.19, Crer des fichiers dinitialisation autonomes et portables, page 414 ;

la recette 16.20, Commencer une configuration personnalise, page 416.

16.15. Aller au fond des choses


Problme
Vous travaillez avec des structures arborescentes troites mais profondes, dans lesquelles
tout le contenu se trouve dans les feuilles et vous ne voulez plus utiliser manuellement
la commande cd avec autant de niveaux.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

400

Chapitre 16 Configurer bash

Solution
alias fond='cd $(dirname $(find . | tail -1))'

Discussion
Cette utilisation de find avec une structure arborescente vaste comme celle de /usr est
dconseille car elle peut prendre beaucoup de temps.
Selon la structure arborescente concerne, cette solution peut ne pas fonctionner ; vous
devez lessayer et constater le rsultat. find . liste simplement tous les fichiers et sousrpertoires du rpertoire de travail. tail -1 rcupre la dernire ligne de la liste.
dirname extrait uniquement le chemin. cd vous y emmne. Il vous est possible dajuster
la commande afin quelle vous place au bon endroit. Par exemple :
alias fond='cd $(dirname $(find . | sort -r | tail -5 | head -1))'
alias fond='cd $(dirname $(find . | sort -r | grep -v 'X11' | tail -3 |
head -1))'

Testez la partie qui se trouve entre les parenthses intrieures, en particulier en ajustant
la commande find, jusqu ce que vous obteniez les rsultats souhaits. Il existe peut-tre
un fichier ou un rpertoire cl en bas de larborescence, auquel cas la fonction suivante
pourrait fonctionner :
function fond { cd $(dirname $(find . | grep -e "$1" | head -1)); }

Notez que les alias nacceptent pas les arguments et que nous avons donc dfini une
fonction. Nous utilisons grep la place dun argument -name find car grep est beaucoup
plus souple. En fonction de votre structure, vous pourriez remplacer tail par head. Une
fois encore, commencez par tester la commande find.

Voir aussi

man find ;

man dirname ;

man head ;

man tail ;

man grep ;

man sort ;

la recette 16.13, Concevoir une meilleure commande cd, page 396 ;

la recette 16.14, Crer un nouveau rpertoire et y aller avec une seule commande, page
398.

16.16. tendre bash avec des commandes


internes chargeables
Le contenu de cette recette apparat galement dans le livre Le shell bash, 3e dition de
Cameron Newman et Bill Rosenblatt (ditions OReilly).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.16. tendre bash avec des commandes internes chargeables

401

Problme
Vous souhaitez que bash ralise certaines tches, mais il nexiste aucune commande interne pour cela. Pour des raisons defficacit, la commande doit tre interne au shell et
non un programme externe. Ou bien, vous disposez dj du code correspondant en C
et vous ne souhaitez pas ou nous pouvez pas le rcrire.

Solution
Utilisez les commandes internes chargeables introduites dans bash version 2.0. Larchive
de bash propose un certain nombre de commandes internes dj crites dans le rpertoire ./examples/loadables/, en particulier le bien connu hello.c. Vous pouvez les compiler
en retirant les lignes correspondant votre systme dans le fichier Makefile, puis en invoquant make. Nous allons prendre lune de ces commandes internes, tty, et nous en servir comme exemple pour ltude gnrale de cette fonctionnalit.
Voici une liste des commandes internes disponibles dans le rpertoire ./examples/
loadables/ de bash version 3.2 :
basename.c
cat.c
cut.c
dirname.c
finfo.c
getconf.c
head.c
hello.c

id.c
ln.c
logname.c
mkdir.c
necho.c
pathchk.c
print.c
printenv.c

push.c
realpath.c
rmdir.c
sleep.c
strftime.c
sync.c
tee.c
template.c

truefalse.c
tty.c
uname.c
unlink.c
whoami.c
perl/bperl.c
perl/iperl.c

Discussion
Sur les systmes qui prennent en charge le chargement dynamique, vous pouvez crire
vos propres commandes internes en C, les compiler en objets partags et les charger
tout moment depuis le shell laide de la commande enable.
Nous allons expliquer rapidement lcriture dune commande interne et son chargement dans bash. Nous supposons que vous savez dj comment crire, compiler et effectuer ldition de liens de programmes C.
tty simule la commande Unix standard tty. Elle affiche le nom du terminal connect
lentre standard. La commande interne, comme la commande standard, renvoie vrai si
le priphrique est de type TTY et faux sinon. De plus, elle prend une option, -s, qui
indique si elle doit travailler silencieusement, cest--dire ne rien afficher et simplement
retourner un rsultat.
Le code C dune commande interne se divise en trois sections distinctes : le code qui implmente la fonctionnalit de la commande interne, la dfinition dun message daide
textuelle et une structure dcrivant la commande interne afin que bash puisse y accder.
La structure de description est assez vidente et prend la forme suivante :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

402

Chapitre 16 Configurer bash

struct builtin nom_commande_struct = {


"nom_commande",
nom_fonction,
BUILTIN_ENABLED,
tablea_aide,
"usage",
0
};

La partie _struct finale est obligatoire sur la premire ligne pour que enable puisse dterminer le nom dy symbole. nom_commande est le nom de la commande interne telle
quelle apparat dans bash. Le champ suivant, nom_fonction, est le nom de la fonction C
qui implmente la commande interne. Nous allons y revenir bientt. BUILTIN_ENABLED
est ltat initial de la commande interne, cest--dire active ou non. Ce champ doit toujours tre fix BUILTIN_ENABLED. tableau_aide est un tableau de chanes de caractres
affiches lorsque help est utilise avec la commande interne. usage est la forme courte
de laide, cest--dire la commande et ses options. Le dernier champ de la structure doit
tre fix 0.
Dans notre exemple, la commande interne se nomme tty, la fonction C tty_builtin
et le tableau daide tty_doc. La chane dutilisation sera tty [-s]. Voici la structure
rsultante :
struct builtin tty_struct = {
"tty",
tty_interne,
BUILTIN_ENABLED,
tty_doc,
"tty [-s]",
0
};

La section suivante contient le code qui se charge du travail :


tty_interne (list)
WORD_LIST *list;
{
int opt, sflag;
char *t;
reset_internal_getopt ( );
sflag = 0;
while ((opt = internal_getopt (list, "s")) != -1)
{
switch (opt)
{
case 's':
sflag = 1;
break;
default:
builtin_usage ( );
return (EX_USAGE);
}

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.16. tendre bash avec des commandes internes chargeables

403

}
list = loptend;
t = ttyname (0);
if (sflag == 0)
puts (t ? t : "non un tty");
return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}

Les fonctions internes reoivent toujours un pointeur sur une liste de type WORD_LIST.
Si la commande interne ne prend aucune option, vous devez appeler no_options(list)
et vrifier sa valeur de retour avant de poursuivre le traitement. Si le code de retour est
diffrent de zro, votre fonction doit sarrter immdiatement avec la valeur EX_USAGE.
Vous devez toujours utiliser internal_getopt et non la fonction getopt de la bibliothque C standard pour traiter les options de la commande interne. De plus, vous devez
commencer par rinitialiser le traitement des options en appelant reset_internal_
getopt.
Le traitement des options se fait de manire standard, except lorsquelles sont invalides,
auquel cas vous devez renvoyer EX_USAGE. Les arguments qui restent aprs le traitement
des options sont dsigns par loptend. Une fois la fonction termine, elle doit renvoyer
la valeur EXECUTION_SUCCESS ou EXECUTION_FAILURE.
Dans le cas de la commande interne tty, nous appelons simplement la routine ttyname
de la bibliothque C standard et, si loption -s est absente, affichons le nom du terminal
TTY (ou non un tty sil nest pas de ce type). La fonction retourne ensuite un code
de succs ou dchec, selon le rsultat de lappel ttyname.
La dernire partie importante est la dfinition de laide. Il sagit simplement dun tableau de chanes de caractres, dont le dernier lment est NULL. Chaque chane est affiche sur la sortie standard lorsque help est excute pour la commande interne. Par
consquent, les chanes doivent comporter 76 caractres au maximum (un affichage
standard de 80 caractres moins une marge de 4 caractres). Dans le cas de tty, le texte
daide est le suivant :
char *tty_doc[] = {
"tty affiche le nom du terminal qui est ouvert pour l'entre et la",
"sortie standard. Si l'option `-s' est indique, rien n'est affich ;",
"le code de sortie dtermine si l'entre standard est connecte ou",
"non un tty.",
(char *)NULL
};

Il ne reste plus qu ajouter notre code les fichiers den-tte C ncessaires. Il sagit de
stdio.h et des fichiers den-tte de bash, config.h, builtins.h, shell.h et bashgetopt.h.
Voici le programme C complet :
// bash Le livre de recettes : tty_interne.c
#include
#include
#include
#include

[05/03/08]

bash Le livre de recettes

"config.h"
<stdio.h>
"builtins.h"
"shell.h"

Elodie FRITSCH <elodie.fritsch@total.com>

404

Chapitre 16 Configurer bash

#include "bashgetopt.h"

extern char *ttyname ( );


tty_interne (list)
WORD_LIST *list;
{
int opt, sflag;
char *t;
reset_internal_getopt ( );
sflag = 0;
while ((opt = internal_getopt (list, "s")) != -1)
{
switch (opt)
{
case 's':
sflag = 1;
break;
default:
builtin_usage ( );
return (EX_USAGE);
}
}
list = loptend;
t = ttyname (0);
if (sflag == 0)
puts (t ? t : "non un tty");
return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
char *tty_doc[] = {
"tty affiche le nom du terminal qui est ouvert pour l'entre et la",
"sortie standard. Si l'option `-s' est indique, rien n'est affich ;",
"le code de sortie dtermine si l'entre standard est connecte ou",
"non un tty.",
(char *)NULL
};
struct builtin tty_struct = {
"tty",
tty_interne,
BUILTIN_ENABLED,
tty_doc,
"tty [-s]",
0
};

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.16. tendre bash avec des commandes internes chargeables

405

Nous devons prsent le compiler et le convertir en objet partag dynamique. Malheureusement, chaque systme dispose de son propre mcanisme de cration des objets partags dynamiques.
Le script configure doit placer automatiquement les commandes adquates dans le fichier Makefile. Sil ny parvient pas, le tableau 16-1 prsente les commandes ncessaires
pour compiler et effectuer ldition de liens de tty.c sur les systmes les plus courants.
Remplacez archive par le chemin de la racine de larchive bash.
Tableau 16-1. Commandes de compilation et ddition de liens de tty.c sur les systmes les plus
rpandus
Systme

Commandes

SunOS 4

cc -pic -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c


ld -assert pure-text -o tty tty.o

SunOS 5

cc -K pic -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c


cc -dy -z text -G -i -h tty -o tty tty.o

SVR4, SVR4.2, Irix

cc -K PIC -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c


ld -dy -z text -G -h tty -o tty tty.o

AIX

cc -K -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c


ld -bdynamic -bnoentry -bexpall -G -o tty tty.o

Linux

cc -fPIC -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c


ld -shared -o tty tty.o

NetBSD, FreeBSD

cc -fpic -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c


ld -x -Bshareable -o tty tty.o

Une fois le programme compil et ldition de liens effectue, vous devez disposer dun
objet partag nomm tty. Pour le charger dans bash, entrez simplement enable -f tty
tty. Vous pouvez tout moment retirer une commande interne charge laide de loption -d, par exemple enable -d tty.
Dans un mme objet partag, il est possible de placer autant de commandes internes
quon le souhaite ; il faut simplement que chacune des commandes internes du mme
fichier C dispose des trois sections principales vues prcdemment. Cependant, il est
prfrable que le nombre de commandes internes par objet partag reste faible. Il peut
tre galement intressant de garder les commandes internes similaires, o les commandes internes qui fonctionnent ensemble (par exemple, pushd, popd, dirs), dans le
mme objet partag.
bash charge un objet partag comme un tout. Ainsi, si vous lui demandez de charger
une commande interne depuis un objet partag qui en contient 20, les 20 commandes
internes sont charges, mais une seule est active. Cest pourquoi il est prfrable que le
nombre de commandes internes reste petit afin de ne pas encombrer la mmoire avec
des commandes inutiles et de regrouper des commandes internes similaires afin que si
lutilisateur souhaite les activer toutes, elles soient dj charges en mmoire et prtes
tre actives.

Voir aussi

./examples/loadables dans larchive des sources de bash version 2.0+.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

406

Chapitre 16 Configurer bash

16.17. Amliorer la compltion programmable


Cette recette est adapte du livre Le shell bash, 3e dition de Cameron Newman et Bill Rosenblatt (ditions OReilly).

Problme
Vous apprciez la compltion programmable de bash, mais vous souhaitez quelle prenne mieux en compte le contexte, en particulier pour les commandes les plus employes.

Solution
Recherchez et installez dautres bibliothques de compltion programmable, ou bien
crivez la vtre. Larchive de bash propose quelques exemples dans ./examples/complete.
Certaines distributions (par exemple, SUSE) disposent de leur propre version dans
/etc/profile.d/complete.bash. Cependant, la bibliothque tiers la plus connue et la plus rpandue est certainement celle de Ian Macdonald. Vous pouvez la tlcharger sous forme darchive ou de RPM http://www.caliban.org/bash/index.shtml#completion ou
http://freshmeat.net/projects/bashcompletion/. Cette bibliothque est dj incluse dans Debian (et ses drivs, comme Ubuntu ou MEPIS) et vous la trouverez dans Fedora Extras,
ainsi que dans dautres dpts tierces parties.
Voici ce que prcise le fichier README de Ian : plusieurs fonctions de
compression supposent lexistence des versions GNU des diffrents utilitaires employs (par exemple, grep, sed et awk) .

Au moment de lcriture de ces lignes, 103 modules sont fournis dans la bibliothque
bash-completion-20060301.tar.gz. En voici une liste partielle :

compltion des alias de bash ;

compltion des variables exportes de bash ;

compltion des fonctions shell de bash ;

compltion pour chown(1) ;

compltion pour chgrp(1) ;

compltion pour if{up,down} sous RedHat & Debian GNU/Linux ;

compltion pour cvs(1) ;

compltion pour rpm(8) ;

compltion pour chsh(1) ;

compltion pour chkconfig(8) ;

compltion pour ssh(1) ;

compltion pour make(1) de GNU ;

compltion pour tar(1) de GNU ;

compltion pour jar(1) ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.17. Amliorer la compltion programmable

compltion pour iptables(8) sous Linux ;

compltion pour tcpdump(8) ;

compltion pour les signets ncftp(1) ;

compltion pour dpkg(8) sous Debian ;

compltion pour Java ;

compltion pour le carnet dadresses de PINE ;

compltion pour mutt ;

compltion pour Python ;

compltion pour Perl ;

compltion pour loutil de gestion des paquets de FreeBSD ;

compltion pour mplayer(1) ;

compltion pour gpg(1) ;

compltion pour dict(1) ;

compltion pour cdrecord(1) ;

compltion pour yum(8) ;

compltion pour smartctl(8) ;

compltion pour vncviewer(1) ;

compltion pour svn.

407

Discussion
La compltion programmable est une fonctionnalit introduite par bash 2.04. Elle tend
la compltion textuelle interne prsente en fournissant un moyen de se brancher au
mcanisme de compltion. Autrement dit, il est virtuellement possible dcrire toute
forme de compltion souhaite. Par exemple, si vous saisissez la commande man, il peut
tre intressant dappuyer sur Tab et dobtenir toutes les sections du manuel. La compltion programmable vous permet de mettre en uvre ce comportement, ainsi que
bien dautres.
Cette recette ne prsente que les bases de la compltion programmable. Si vous devez
entrer dans son fonctionnement interne et crire du code pour ltendre, commencez
par examiner les bibliothques de compltion dveloppes par dautres programmeurs.
Elles proposent peut-tre la fonctionnalit que vous recherchez. Nous allons simplement survoler les commandes et les procdures de base ncessaires au mcanisme de
compltion pour le cas o vous devriez un jour travailler avec.
Pour pouvoir effectuer une compltion textuelle de manire spcifique, vous devez
commencer par indiquer au shell comment il doit y procder lorsque vous appuyez sur
la touche Tab. Cela se fait par la commande complete.
Largument principal de complete est un nom qui peut reprsenter une commande ou
toute autre chose laquelle doit sappliquer la compltion. Comme exemple, nous allons examiner la commande gunzip qui permet de dcompresser des archives de diffrents types. Normalement, si vous saisissez :
$ gunzip [TAB][TAB]
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

408

Chapitre 16 Configurer bash

vous devez obtenir une liste de noms de fichiers qui peuvent servir complter la commande. Cette liste inclut mme des choses qui ne peuvent tre employes avec la commande gunzip. En ralit, nous prfrerions avoir un sous-ensemble des fichiers que la
commande est capable de traiter. Pour cela, nous pouvons utiliser complete :
complete -A file -X '!*.@(Z|gz|tgz)' gunzip

Pour que @(Z|gz|tgz) soit accept, vous devez activer la correspondance de motif tendue laide de shopt -s extglob.
Nous indiquons au mcanisme de compltion que si la commande gunzip est saisie,
nous souhaitons un traitement spcifique. Loption -A reprsente une action et prend
diffrents arguments. Dans ce cas, nous lui passons file afin dindiquer au mcanisme
de fournir une liste de fichiers susceptibles de complter la commande. Ltape suivante
est de rduire cette liste afin de ne garder que les fichiers qui peuvent tre traits par
gunzip. Pour cela, nous utilisons loption -X qui prend en argument un motif de filtre.
Lorsquil est appliqu la liste de compltion, le filtre retire tous les lments qui ne
correspondent pas au motif. gunzip peut dcompresser diffrents types de fichiers y compris ceux dont lextension est .Z, .gz ou .tgz. Nous souhaitons garder uniquement tous
les noms de fichiers dont lextension correspond lun de ces trois motifs. Nous devons
donc prendre linverse du rsultat avec ! (noubliez pas que le filtre retire tous les lments correspondant au motif).
Nous pouvons tester cette solution et voir les compltions obtenues sans passer par
linstallation de la compltion avec complete. Pour cela, nous utilisons la commande
compgen :
compgen -A file -X '!*.@(Z|gz|tgz)'

Elle produit une liste des chanes de compltion (si lon suppose que le rpertoire courant contient des fichiers avec ces extensions). compgen permet de tester des filtres en
renvoyant les chanes de compltion ainsi produites. Elle est galement indispensable
lorsquune compltion plus complexe est requise. Nous en verrons un exemple plus
loin dans cette recette.
Une fois la commande complete prcdente installe, soit en la plaant dans un script,
soit en lexcutant depuis la ligne de commande, nous pouvons utiliser le mcanisme
de compltion amliore avec la commande gunzip :
$gunzip [TAB][TAB]
archive.tgz archive1.tgz
$gunzip

fichier.Z

Vous imaginez certainement les autres choses que nous pourrions faire. Par exemple,
pourquoi ne pas fournir une liste des arguments possibles certaines options dune
commande ? La commande kill peut prendre en argument un identifiant de processus,
mais galement un nom de signal prcd dun tiret (-) ou un nom de signal suivi de
loption -n. Il est intressant de pouvoir complter la commande par des identifiants
ou, en prsence dun tiret ou de -n, par des noms de signaux.
Cet exemple est un peu plus complexe que le prcdent. Nous avons besoin de code
pour dterminer ce qui a dj t saisi. Nous avons galement besoin de rcuprer les
identifiants de processus et les noms de signaux. Nous allons placer ce code dans une
fonction, qui sera appele via le mcanisme de compltion. Voici le code qui appelle notre fonction, nomme _kill :
complete -F _kill kill
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.17. Amliorer la compltion programmable

409

Loption -F de complete indique dappeler la fonction _kill lorsque la compltion textuelle se fait sur la commande kill. Voici le code de la fonction :
# bash Le livre de recettes : fonc_kill
_kill() {
local cour
local symb
COMPREPLY=( )
cour=${COMP_WORDS[COMP_CWORD]}
if (($COMP_CWORD == 2)) && [[ ${COMP_WORDS[1]} == -n ]]; then
# Retourner la liste des signaux disponibles.
_signaux
elif (($COMP_CWORD == 1 )) && [[ "$cour" == -* ]]; then
# Retourner la liste des signaux disponibles.
symb="-"
_signaux
else
# Retourner la liste des identifiants de processus disponibles.
COMPREPLY=( $( compgen -W '$( command ps axo pid | sed 1d )' $cour ) )
fi
}

Le code est assez standard, lexception de certaines variables denvironnement spciales et dun appel la fonction _signaux, que nous verrons ci-aprs.
La variable $COMPREPLY est utilise pour stocker le rsultat renvoy au mcanisme de
compltion. Il sagit dun tableau contenant un ensemble de chanes de compltion,
vid au dbut de la fonction.
La variable locale $cour permet de rendre le code plus lisible car sa valeur est employe
diffrents endroits. Sa valeur drive dun lment du tableau $COMP_WORDS. Celui-ci
contient chaque mot de la ligne de commande courante. $COMP_CWORD est un indice
dans ce tableau ; il dsigne le mot sur lequel se trouve le curseur. $cour contient le mot
sur lequel se trouve le curseur.
La premire instruction if vrifie si la commande kill est suivie de loption -n. Si le premier mot est -n et si nous nous trouvons sur le deuxime mot, nous devons fournir une
liste des noms de signaux au mcanisme de compltion.
La deuxime instruction if est similaire, mais, cette fois, nous cherchons complter le
mot courant, qui commence par un tiret suivi de caractres quelconques. Le corps de ce
if appelle nouveau _signaux mais la valeur de la variable $symb est maintenant un
tiret. La raison deviendra vidente lorsque nous examinerons la fonction _signaux.
Le code dans le bloc else renvoie une liste didentifiants de processus. Il utilise la commande compgen pour faciliter la cration du tableau des chanes de compltion. Tout
dabord, la commande ps est excute afin dobtenir la liste des identifiants de processus, puis le rsultat est pass sed afin de retirer la premire ligne qui contient un entte. Le rsultat est donn en argument loption -W de compgen, qui prend une liste de
mots. compgen retourne ensuite toutes les chanes de compltion qui correspondent la
valeur de la variable $cour et le tableau rsultant est affect $COMPREPLY.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

410

Chapitre 16 Configurer bash

compgen est importante ici car nous ne pouvons simplement renvoyer la liste complte
des identifiants de processus fournie par ps. Lutilisateur peut avoir dj saisi une partie
dun identifiant et demand la compltion. Avec la valeur partielle de lidentifiant de
processus stocke dans la variable $cour, compgen limite les rsultats ceux qui correspondent cette valeur. Par exemple, si $cour contient la valeur 5, alors compgen ne renvoie que les identifiants de processus commenant par 5 , comme 5, 59 ou 562.
Le dernier lment du puzzle est la fonction _signaux :
# bash Le livre de recettes : fonc_signaux
_signaux() {
local i
COMPREPLY=( $( compgen -A signal SIG${cour#-} ))
for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
COMPREPLY[i]=$symb${COMPREPLY[i]#SIG}
done
}

Mme si nous pouvons obtenir une liste des noms de signaux laide de complete -A signal, ils ne sont malheureusement pas dans une forme trs utilisable et nous ne pouvons nous en servir pour gnrer directement le tableau des noms. Les noms gnrs
commencent par les lettres SIG , contrairement aux noms accepts par la commande
kill. La fonction _signaux doit affecter $COMPREPLY un tableau de noms de signaux, optionnellement prcds dun tiret.
Tout dabord, nous gnrons la liste des noms de signaux avec compgen. Chaque nom
commence par SIG . Afin que compgen fournisse le sous-ensemble adquat si lutilisateur a commenc entrer un nom, nous ajoutons SIG au dbut de la valeur de
$cour. Nous en profitons galement pour enlever tout tiret qui pourrait se trouver au
dbut de la valeur.
Ensuite, nous parcourons le tableau afin de supprimer les lettres SIG de ses lments et dajouter, si ncessaire, un tiret (la valeur de la variable $symb) chaque entre.
complete et compgen ont beaucoup dautres options et actions, bien plus que ne nous
pouvons en dcrire ici. Si vous tes intress par la compltion programmable, nous
vous conseillons de lire le manuel de bash et de tlcharger les nombreux exemples disponibles sur Internet ou dans larchive de bash dans ./examples/complete.

Voir aussi

help complete ;

help compgen ;

./examples/complete dans larchive des sources de bash version 2.04+ ;

http://www.caliban.org/bash/index.shtml#completion ;

http://freshmeat.net/projects/bashcompletion.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.18. Utiliser correctement les fichiers dinitialisation

411

16.18. Utiliser correctement les fichiers


dinitialisation
Problme
Vous souhaitez connatre le rle de tous les fichiers dinitialisation, ou rc.

Solution
Vous trouverez ci-aprs la liste des fichiers et leur utilisation. Certains dentre eux, voire
tous, pourront tre absents de votre systme, en fonction de sa configuration. Les systmes qui utilisent bash par dfaut (par exemple, Linux) disposent gnralement du jeu
complet. Il manquera certains fichiers sur les systmes qui emploient par dfaut un
autre shell.
/etc/profile
Le fichier denvironnement global douverture de session pour les shells Bourne et
similaires. Nous vous conseillons de ne pas y toucher, moins que vous soyez
ladministrateur systme et que vous sachiez ce que vous faites.
/etc/bashrc (Red Hat) /etc/bash.bashrc (Debian)
Le fichier denvironnement global pour les sous-shells bash interactifs. Nous vous
conseillons de ne pas y toucher, moins que vous soyez ladministrateur systme et
que vous sachiez ce que vous faites.
/etc/bash_completion
Sil existe, il sagit trs certainement du fichier de configuration de la bibliothque
de compltion programmable de Ian Macdonald (voir la recette 16.17, page 406).
Vous pouvez lexaminer, il est trs intressant.
/etc/inputrc
Le fichier de configuration globale de GNU Readline. Nous vous recommandons
de lajuster comme souhait pour la globalit du systme (si vous tes ladministrateur) ou dadapter ~/.inputrc vos besoins propres (voir la recette 16.20, page 416). Il
nest pas excut ni charg avec source, mais lu via Readline et $INPUTRC, ainsi que
par $include (ou bind -f). Notez quil peut contenir des instructions include pour
lire dautres fichiers Readline.
~/.bashrc
Le fichier denvironnement personnel pour les sous-shells bash interactifs. Nous
vous conseillons dy placer vos alias, fonctions et autres invites.
~/.bash_profile
Le fichier de profil personnel pour les shells bash douverture de session. Vous
devez vrifier quil charge bien ~/.bashrc, puis ignorez-le.
~/.bash_login
Le fichier de profil personnel pour les shells Bourne douverture de session. Il est
utilis par bash uniquement si ~/.bash_profile nexiste pas. Nous vous recommandons de lignorer.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

412

Chapitre 16 Configurer bash

~/.profile
Le fichier de profil personnel pour les shells Bourne douverture de session. Il est
utilis par bash uniquement si ~/.bash_profile et ~/.bash_login nexistent pas. Nous
vous recommandons de lignorer, sauf si vous utilisez galement dautres shells qui
en ont besoin.
~/.bash_history
Le fichier par dfaut pour lenregistrement de lhistorique des commandes du shell.
Nous vous conseillons dutiliser les outils de gestion de lhistorique (voir la recette
16.12, page 393) pour le manipuler et non de le modifier directement. Il nest pas
excut ni charg avec source, il sagit simplement dun fichier de donnes.
~/.bash_logout
Ce fichier est excut lors de la fermeture de session. Nous vous conseillons dy placer vos routines de nettoyage (voir la recette 17.7, page 438). Il nest excut que si la
session est ferme de manire propre (cest--dire, si elle ne se termine pas suite
une perte de connexion rseau).
~/.inputrc
Le fichier des personnalisations individuelles de GNU Readline. Nous vous conseillons de ladapter vos besoins (voir la recette 16.20, page 416). Il nest pas excut ni charg avec source, mais lu via Readline et $INPUTRC, ainsi que par $include
(ou bind -f). Notez quil peut contenir des instructions include pour lire dautres
fichiers Readline.
Nous savons bien que cette liste est un peu complique suivre. Cependant, chaque systme dexploitation ou distribution peut se comporter diffremment puisque cest le
fournisseur qui dcide du contenu de ces fichiers. Pour rellement comprendre le fonctionnement de votre systme, examinez chacun deux. Vous pouvez galement ajouter
temporairement une commande echo nom_du_fichier >&2 la toute premire ligne des
fichiers qui sont excuts ou chargs avec source (tous sauf /etc/inputrc, ~/.inputrc et
~/.bash_history). Sachez cependant que cela peut interfrer avec dautres programmes
(en particulier scp et rsync) qui sont perturbs par des informations supplmentaires sur
STDOUT ou STDERR. Vous devez donc retirer ces instructions lorsque votre tude est
termine. Pour plus de dtails, consultez lavertissement de la recette 16.19, page 414.
Utilisez le tableau 16-2 uniquement comme un guide, car votre systme peut fonctionner diffremment. (Outre les fichiers rc associs louverture de session et donnes au
tableau 16-2, le fichier ~/.bash_logout est utilis lorsque une session interactive se termine
proprement.)
Pour plus dinformations, consultez la section Bash Startup Files du manuel de rfrence de bash (http://www.gnu.org/software/bash/manual/bashref.html).

Discussion
Sous Unix ou Linux, il est assez difficile de savoir o modifier quelque chose, comme la
variable $PATH ou une invite, lorsque cela doit concerner lintgralit du systme. Selon
les systmes dexploitation et leurs versions, les paramtres peuvent se trouver en diffrents endroits. La commande suivante a de fortes chances de trouver lemplacement de
la dfinition de la variable $PATH du systme :
$ grep 'PATH=' /etc/{profile,*bash*,*csh*,rc*}
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.18. Utiliser correctement les fichiers dinitialisation

413

Tableau 16-2. Fichiers rc de bash sous Ubuntu 6.10 et Fedora Core 5


Shell interactif
douverture de
session

Shell interactif non


douverture de
session (bash)

(Script) shell non


interactif (/dev/null
de bash)

Non interactif
(bash -c :)

Ubuntu 6.10 :
/etc/profile
/etc/bash.bashrc
~/.bash_profilea
~/.bashrc
/etc/bash_completion

Ubuntu 6.10 :

Ubuntu 6.10 :
Sans objet (SO)

Ubuntu 6.10 :
SO

Fedora Core 5 :
/etc/profilebc
/etc/profile.d/colorls.sh
/etc/profile.d/glib2.sh
/etc/profile.d/krb5.sh
/etc/profile.d/lang.sh
/etc/profile.d/less.sh
/etc/profile.d/vim.sh
/etc/profile.d/which-2.sh
~/.bash_profilea
~/.bashrc
/etc/bashrc

Fedora Core 5 :

Fedora Core 5 :
SO

Fedora Core 5 :
SO

/etc/bash.bashrc
~/.bashrc
/etc/bash_completion

~/.bashrc
/etc/bashrc

a. Si ~/.bash_profile nexiste pas, alors ~/.bash_login ou ~/.profile sont consults, dans cet ordre.
b. Si $INPUTRC nest pas dfinie et si ~/.inputrc nexiste pas, fixez $INPUTRC /etc/inputrc.
c. /etc/profile de Red Hat charge galement les fichiers /etc/profile.d/*.sh ; voir la recette 4.10,
page 82.

Si elle ne fonctionne pas, il ne vous reste plus qu invoquer grep sur tout /etc :
# find /etc -type f | xargs grep 'PATH='

Contrairement la plupart du code prsent dans ce livre, il est prfrable dexcuter


cette commande en tant que root. Si vous linvoquez en tant quutilisateur normal, vous
obtiendrez des rsultats, mais vous passerez ct de certains fichiers et recevrez certainement des erreurs Permission non accorde .
Il est galement difficile de savoir ce qui peut tre ajust pour votre compte personnel
et o placer ces modifications. Nous esprons que ce chapitre vous a apport de nombreuses ides quant ce problme.

Voir aussi

man grep ;

man find ;

man xargs ;

la section Bash Startup Files du manuel de rfrence de bash (http://www.gnu.


org/software/bash/manual/bashref.html) ;

la recette 16.3, Modifier dfinitivement $PATH, page 376 ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

414

Chapitre 16 Configurer bash

la recette 16.12, Fixer les options de lhistorique du shell, page 393 ;

la recette 16.17, Amliorer la compltion programmable, page 406 ;

la recette 16.19, Crer des fichiers dinitialisation autonomes et portables, page 414 ;

la recette 16.20, Commencer une configuration personnalise, page 416 ;

la recette 17.7, Effacer lcran lorsque vous vous dconnectez, page 438.

16.19. Crer des fichiers dinitialisation


autonomes et portables
Problme
Vous travaillez sur diffrentes machines, avec, pour certaines, des droits limits ou un
accs root complet. Vous souhaitez reproduire un environnement bash cohrent, tout en
gardant la possibilit de paramtres personnaliss par systme dexploitation, machines
ou autres critres (par exemple, domicile ou bureau).

Solution
Placez toutes vos adaptations dans des fichiers dans un sous-rpertoire configurations.
Copiez, ou utilisez rsync, ce rpertoire dans un emplacement comme ~/ ou /etc, et utilisez des inclusions et des liens symboliques (par exemple, ln -s ~/configurations/screenrc ~/.screenrc) selon les besoins. Appliquez une logique vos fichiers de
personnalisation afin de prendre en compte des critres comme le systme dexploitation, lemplacement, etc.
Vous pouvez galement dcider de ne pas commencer les noms de fichiers par un point
afin quils soient plus faciles grer. Comme la expliqu la recette 1.5, page 10, lorsque
le nom dun fichier commence par un point, ls naffiche pas le fichier, allgeant ainsi la
liste du contenu de votre rpertoire personnel. Mais, puisque nous utilisons ce rpertoire uniquement pour conserver des fichiers de configuration, lutilisation du point nest
pas ncessaire. Pour la mme raison, le point nest gnralement pas employ avec les
fichiers de /etc.
La recette 16.20, page 416, donne un exemple sur lequel vous pouvez vous appuyer.

Discussion
Voici les hypothses et les critres ayant servi au dveloppement de la solution.

Hypothses

vous vous trouvez dans un environnement complexe, dans lequel vous contrlez
certaines machines, mais pas toutes ;

pour les machines dont vous assurez la gestion, lune exporte /opt/bin et toutes les
autres montent ce rpertoire par NFS. Tous les fichiers de configuration sy trouvent donc. Nous avons utilis /opt/bin car il est court et risque moins dentrer en

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.19. Crer des fichiers dinitialisation autonomes et portables

415

conf lit avec des rpertoires existants que /usr/local/bin. Vous pouvez choisir ce que
vous voulez ;

pour les machines partiellement contrles, vous utilisez un fichier de configuration de niveau systme dans /etc ;

pour les machines sur lesquelles vous navez aucun droit dadministration, les
fichiers commenant par un point sont utiliss dans ~/ ;

certains paramtres varient dune machine lautre et selon lenvironnement (par


exemple, domicile ou bureau).

Critres

le dplacement des fichiers de configuration dun systme dexploitation ou dun


environnement lautre ne doit demander quun nombre rduit de modifications ;

les configurations par dfaut du systme dexploitation ou celles de ladministrateur


systme doivent tre compltes et non remplaces ;

il faut une souplesse suffisante permettant de grer les demandes faites par des configurations conf lictuelles (par exemple, CVS au domicile et au bureau).
Sil est tentant de placer des instructions echo dans les fichiers de configuration pour voir ce qui sy passe, soyez prudent. En procdant ainsi,
les commandes scp, rsync et probablement tout autre programme de
type rsh choueront avec des erreurs tranges :
scp
protocol error: bad mode
rsync
protocol version mismatch - is your shell clean?
(see the rsync manpage for an explanation)
rsync error: protocol incompatibility (code 2) at compat.c(62)

ssh fonctionne parfaitement car il est interactif et la sortie est affiche


lcran au lieu de perturber le flux de donnes. Pour plus dinformations sur ce comportement, consultez la section Discussion de la recette
14.22, page 329.

Pour le dbogage, placez les deux lignes suivantes au dbut de /etc/profile ou de


~/.bash_profile, mais lisez bien lavertissement concernant la perturbation du flux de
donnes :
export PS4='+xtrace $LINENO: '
set -x

la place, o en plus de set -x, vous pouvez ajouter les lignes suivantes dans les fichiers
de votre choix :
# Par exemple, dans ~/.bash_profile :
case "$-" in
*i*) echo "$(date '+%Y-%m-%d_%H:%M:%S_%Z') Mode
"~/.bash_profile ssh=$SSH_CONNECTION"
* ) echo "$(date '+%Y-%m-%d_%H:%M:%S_%Z') Mode
"~/.bash_profile ssh=$SSH_CONNECTION"
esac
[05/03/08]

bash Le livre de recettes

interactif" \
>> ~/rc.log ;;
non interactif" \
>> ~/rc.log ;;

Elodie FRITSCH <elodie.fritsch@total.com>

416

Chapitre 16 Configurer bash

# Dans ~/.bashrc :
case "$-" in
*i*) echo "$(date '+%Y-%m-%d_%H:%M:%S_%Z') Mode interactif" \
"~/.bashrc ssh=$SSH_CONNECTION" >> ~/rc.log ;;
* ) echo "$(date '+%Y-%m-%d_%H:%M:%S_%Z') Mode non interactif" \
"~/.bashrc ssh=$SSH_CONNECTION" >> ~/rc.log ;;
esac

Puisquelles nenvoient aucune sortie sur le terminal, ces commandes ne crent pas les
interfrences nfastes dcrites dans lavertissement. Excutez une commande tail -f
~/rc.log dans une session et la commande problmatique (par exemple, scp, cvs)
ailleurs afin de dterminer les fichiers de configuration en cours dutilisation. Vous
pourrez par la suite dterminer plus facilement le problme.
Lorsque vous apportez des modifications vos fichiers de configuration, nous vous conseillons fortement douvrir deux sessions. Effectuez tous les changements dans une session, fermez-la et ouvrez-la nouveau. Si les modifications vous empchent douvrir
une nouvelle session, apportez les corrections ncessaires depuis la deuxime session et
essayez nouveau de vous connecter. Ne quittez pas les deux terminaux tant que vous
ntes pas absolument certain de pouvoir vous reconnecter. Cette mthode est particulirement importante si vos modifications affectent le compte root.
Vous ntes pas rellement oblig de fermer et douvrir nouveau la session. Vous pouvez charger les fichiers modifis avec source, mais des restes provenant de lenvironnement prcdent peuvent faire que tout fonctionne temporairement, jusqu ce que vous
ouvriez une nouvelle session et constatiez le dysfonctionnement. Apportez les modifications lenvironnement en cours dexcution, mais ne modifiez les fichiers que lorsque vous tes prt faire les tests. Dans le cas contraire, vous pourriez tre bloqu.

Voir aussi

la recette 1.5, Afficher tous les fichiers cachs, page 10 ;

la recette 14.23, Dconnecter les sessions inactives, page 331 ;

la recette 16.18, Utiliser correctement les fichiers dinitialisation, page 411 ;

la recette 16.20, Commencer une configuration personnalise, page 416.

16.20. Commencer une configuration


personnalise
Problme
Vous souhaitez adapter votre environnement mais vous ne savez pas vraiment par o
commencer.

Solution
Voici quelques exemples qui vous donneront une ide des diverses possibilits. Nous
suivons les conseils de la recette 16.19, page 414, et conservons les personnalisations spares afin de pouvoir faire marche arrire et faciliter la portabilit entre les systmes.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.20. Commencer une configuration personnalise

417

Pour les profils de niveau systme, ajoutez les instructions dans /etc/profile. Puisque ce
fichier est galement employ par le vritable shell Bourne, faites attention ne pas utiliser des fonctionnalits rserves bash (par exemple, source la place de .) si vous tes
sur un systme non-Linux. Sur ce systme, bash est le shell par dfaut pour /bin/sh et
/bin/bash (sauf exception, comme avec Ubuntu 610+, qui opte pour dash). Pour les paramtres de niveau utilisateur, modifiez lun des fichiers ~/.bash_profile, ~/.bash_login ou
~/.profile, dans cet ordre, selon celui qui existe dj :
# bash Le livre de recettes : ajouter_a_bash_profile
# Si nous utilisons bash, rechercher notre configuration et la
# charger. Il est galement possible de figer $CONFIGURATIONS,
# mais notre mthode est plus souple.
if [ -n "$BASH_VERSION" ]; then
for chemin in /opt/bin /etc ~ ; do
# Utiliser le premier trouv.
if [ -d "$chemin/CONFIGURATIONS" -a -r "$chemin/CONFIGURATIONS" -a -x
"$chemin/CONFIGURATIONS" ]
then
export CONFIGURATIONS="$chemin/CONFIGURATIONS"
fi
done
source "$CONFIGURATIONS/bash_profile"
#source "$CONFIGURATIONS/bash_rc"
# Si ncessaire.
fi

Pour les paramtres denvironnement de niveau systme, ajoutez le code suivant dans
/etc/bashrc (ou /etc/bash.bashrc) :
# bash Le livre de recettes : ajouter_a_bashrc
# Si nous utilisons bash et si ce n'est dj fait, rechercher notre
# configuration et la charger. Il est galement possible de figer
# $CONFIGURATIONS, mais notre mthode est plus souple.
if [ -n "$BASH_VERSION" ]; then
if [ -z "$CONFIGURATIONS" ]; then
for chemin in /opt/bin /etc ~ ; do
# Utiliser le premier trouv
if [ -d "$chemin/configurations" -a -r "$chemin/configurations"
-a -x "$chemin/configurations" ]
then
export CONFIGURATIONS="$chemin/configurations"
fi
done
fi
source "$CONFIGURATIONS/bashrc"
fi

Exemple de fichier bash_profile :


# bash Le livre de recettes : bash_profile
# configurations/bash_profile : paramtres d'environnement pour un

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

418

Chapitre 16 Configurer bash

# shell d'ouverture de session.


# Pour le relire (et utiliser les modifications de ce fichier) :
# source $CONFIGURATIONS/bash_profile
#
#
#
#
#
:

Prise en compte des dfaillances. Cette variable doit tre dfinie


avant l'excution de cette configuration, mais, si ce n'est pas
le cas, le message d'erreur "non trouv" doit tre assez parlant.
Utiliser un ':' initial afin d'viter l'excution de la ligne
comme un programme aprs son dveloppement.
${CONFIGURATIONS:='variable_CONFIGURATIONS_non_dfinie'}

#
#
#
#

Dbogage uniquement - perturbe scp, rsync.


echo "Lecture de $CONFIGURATIONS/bash_profile..."
export PS4='+xtrace $LINENO : '
set -x

# Dbogage/journalisation - sans effet sur scp, rsync.


#case "$-" in
#
*i*) echo "$(date '+%Y-%m-%d_%H:%M:%S_%Z') Mode interactif" \
#
"$CONFIGURATIONS/bash_profile ssh=$SSH_CONNECTION" >> ~/rc.log
;;
#
* ) echo "$(date '+%Y-%m-%d_%H:%M:%S_%Z') Mode non interactif" \
#
"$CONFIGURATIONS/bash_profile ssh=$SSH_CONNECTION" >> ~/rc.log
;;
#esac
# Utiliser le script keychain (http://www.gentoo.org/proj/en/keychain/)
# pour grer ssh-agent, si disponible. Sinon, il faut l'installer.
for chemin in $CONFIGURATIONS ${PATH//:/ }; do
if [ -x "$chemin/keychain" ]; then
# Charger les cls par dfaut id_rsa et/ou id_dsa, en ajouter
# d'autres selon les besoins.
# Voir aussi --clear --ignore-missing --noask --quiet --time-out
$chemin/keychain ~/.ssh/id_?sa
break
fi
done

# Appliquer galement la personnalisation du sous-shell interactif


# aux shells d'ouverture de session. Le fichier profile du systme
# plac dans /etc le fait probablement dj. Si ce n'est pas le cas,
# il est sans doute prfrable de procder manuellement :
# source "$CONFIGURATIONS/bash_profile"
# Mais, au cas o...
#for fichier in /etc/bash.bashrc /etc/bashrc ~/.bashrc; do
#
[ -r "$fichier" ] && source $fichier && break # Utiliser le
#
# premier trouv.
#done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.20. Commencer une configuration personnalise


# Raliser des oprations
case $HOSTNAME in
*.societe.fr
) #
;;
hote1.*
) #
;;
hote2.societe.fr ) #
;;
drake.*
) #
;;
esac

#
#
#
#

419

propres au site ou la machine.


source $CONFIGURATIONS/societe.fr
contenu pour hote1.
source .bashrc.hote2
echo DRAKE dans bash_profile.jp !

Faire la suite en dernier ici car nous avons une birfurcation.


Si nous quittons screen, nous revenons une session pleinement
configure. La session screen est galement configure et si
nous ne la quittons jamais cette session sera acceptable.

# N'excuter que si screen n'est pas dj en cours et si le fichier


# '~/.use_screen' existe.
if [ $TERM != "screen" -a "$USING_SCREEN" != "YES" -a -f ~/.use_screen ];
then
# Nous devrions plutt utiliser 'type -P' ici, mais cette
# commande est arrive avec bash-2.05b et nous utilisons des
# systmes que nous ne contrlons pas, avec des versions
# plus anciennes. Nous ne pouvons pas employer facilement
# 'which' puisque, sur certains systmes, nous obtenons
# une sortie, que le fichier soit trouv ou non.
for chemin in ${PATH//:/ }; do
if [ -x "$chemin/screen" ]; then
# Si screen(1) existe et est excutable, lancer
# notre enveloppe.
[ -x "$CONFIGURATIONS/lancer_screen" ] &&
$CONFIGURATIONS/lancer_screen
fi
done
fi

Exemple de fichier bashrc (il est long, mais lisez-le pour reprendre certaines ides) :
# bash Le livre de recettes : bashrc
#
#
#
#

configurations/bash_profile : paramtres d'environnement


pour un sous-shell.
Pour le relire (et utiliser les modifications de ce fichier) :
source $CONFIGURATIONS/bashrc

#
#
#
#

Prise en compte des dfaillances. Cette variable doit tre dfinie


avant l'excution de cette configuration, mais, si ce n'est pas
le cas, le message d'erreur "non trouv" doit tre assez parlant.
Utiliser un ':' initial afin d'viter l'excution de la ligne

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

420

Chapitre 16 Configurer bash

# comme un programme aprs son dveloppement.


: ${CONFIGURATIONS:='variable_CONFIGURATIONS_non_dfinie'}
#
#
#
#

Dbogage uniquement - perturbe scp, rsync.


echo "Lecture de $CONFIGURATIONS/bashrc..."
export PS4='+xtrace $LINENO: '
set -x

# Dbogage/journalisation - sans effet sur scp, rsync.


#case "$-" in
#
*i*) echo "$(date '+%Y-%m-%d_%H:%M:%S_%Z') Mode interactif" \
#
"$CONFIGURATIONS/bashrc ssh=$SSH_CONNECTION" >> ~/rc.log ;;
#
* ) echo "$(date '+%Y-%m-%d_%H:%M:%S_%Z') Mode non interactif" \
#
"$CONFIGURATIONS/bashrc ssh=$SSH_CONNECTION" >> ~/rc.log ;;
#esac
#
#
#
#
#

En thorie, le contenu suivant est galement charg depuis


/etc/bashrc (/etc/bash.bashrc) ou ~/.bashrc pour l'appliquer
aux shells d'ouverture de session. En pratique, si ces paramtres
fonctionnent uniquement certaines fois (comme dans les sous-shells),
vrifiez ce point.

# Dfinir quelques invites utiles.


# Invite pour la ligne de commande interactive.
# Dfinir uniquement l'une des invites si nous sommes rellement
# en mode interactif, car certains utilisateurs effectuent le
# test suivant pour dterminer si le shell est en mode interactif :
# if [ "$PS1" ]; then
case "$-" in
*i*)
#export PS1='\n[\u@\h t:\l l:$SHLVL h:\! j:\j v:\V]\n$PWD\$ '
#export PS1='\n[\u@\h:T\l:L$SHLVL:C\!:\D{%Y-%m%d_%H:%M:%S_%Z}]\n$PWD\$ '
export PS1='\n[\u@\h:T\l:L$SHLVL:C\!:J\j:\D{%Y-%m%d_%H:%M:%S_%Z}]\n$PWD\$ '
#export PS2='> '
# Invite secondaire.
#export PS3='Faites votre choix : ' # Invite de select.
export PS4='+xtrace $LINENO : '
# Invite de xtrace (dbogage).
;;
esac
# S'assurer que le fichier inputrc personnalis est utilis, si nous
# le trouvons (remarquer les diffrents noms). L'ordre est prcis,
# puisque, dans ce cas, nous voulons que nos paramtres remplacent
# ceux du systme, sil y en a.
for fichier in $CONFIGURATIONS/inputrc ~/.inputrc /etc/inputrc; do
# Utiliser le premier trouv.
[ -r "$fichier" ] && export INPUTRC="$fichier" && break
done

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.20. Commencer une configuration personnalise

421

# Ne pas gnrer de fichiers core.


# Voir aussi /etc/security/limits.conf sur de nombreux systmes Linux.
ulimit -S -c 0 > /dev/null 2>&1
# Empcher CTRL-D de quitter le shell.
set -o ignoreeof
# Personnaliser l'historique du shell.
export HISTSIZE=5000
# Nb commandes dans l'historique en mmoire.
export HISTFILESIZE=5000
# Nb commandes dans le fichier d'historique.
export HISTCONTROL=ignoreboth # bash < 3, omettre les doublons & les lignes
# commenant par une espace.
export HISTIGNORE='&:[ ]*'
# bash >= 3, mettre les doublons & les lignes
# commenant par une espace.
#export HISTTIMEFORMAT='%Y-%m-%d_%H:%M:%S_%Z=' # bash >= 3, estampille
# temporelle dans le fichier d'historique.
shopt -s histappend
# Ajouter et non craser l'historique en
# fin de session.
shopt -q -s cdspell
# Corriger automatiquement les fautes
# mineures dans l'utilisation interactive
# de 'cd'.
shopt -q -s checkwinsize
# Actualiser les valeurs de LINES et COLUMNS.
shopt -q -s cmdhist
# Convertir les commandes multi-lignes en
# une ligne dans l'historique.
set -o notify
# (ou set -b) # Notification immdiate de la fin d'une
# tche en arrire-plan.
# Autres paramtres de bash.
export LC_COLLATE='C'
# Utiliser l'ordre de tri C classique
# (ex., les majuscules en premier).
export HOSTFILE='/etc/hosts' # Utiliser /etc/hosts pour la compltion
# des noms d'htes.
export CDPATH='~/:.:..:../..' # Similaire $PATH, mais pour 'cd'.
# Noter que '.' dans $CDPATH est ncessaire pour que la commande cd
# fonctionne en mode POSIX, mais elle affiche alors le nouveau
# rpertoire sur STDOUT !
#
#
#
#
#
#

Importer les paramtres de compltion de bash, s'ils existent dans


l'emplacement par dfaut. Sur un systme lent, cette opration peut
prendre un peu de temps. Vous pouvez donc la retirer, mme si le
fichier existe (ce qui n'est pas le cas pas dfaut sur de nombreux
systmes, comme Red Hat).
[ -r /etc/bash_completion ] && source /etc/bash_completion

# Utiliser un filtre lesspipe, si nous le trouvons. Cela dfinit la


# variable $LESSOPEN. Remplacer globalement le dlimiteur ':' de
# $PATH par une espace pour une utilisation dans une liste.
for chemin in $CONFIGURATIONS /opt/bin ~/ ${PATH//:/ }; do
# Utiliser le premeir trouv , entre 'lesspipe.sh' (prfr)
# et 'lesspipe' (Debian).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

422

Chapitre 16 Configurer bash

[ -x "$chemin/lesspipe.sh" ] && eval $("$chemin/lesspipe.sh") && break


[ -x "$chemin/lesspipe" ]
&& eval $("$chemin/lesspipe")
&& break
done
# Dfinir d'autres prfrences pour less et l'diteur.
export LESS="--LONG-PROMPT --LINE-NUMBERS --QUIET"
export VISUAL='vi' # Un diteur par dfaut, normalement toujours
# disponible.
# Nous devrions plutt utiliser 'type -P' ici, mais cette commande est
# arrive avec bash-2.05b et nous utilisons des systmes que nous ne
# contrlons pas, avec des versions plus anciennes. Nous ne pouvons pas
# employer facilement 'which' puisque, sur certains systmes, nous
# obtenons une sortie, que le fichier soit trouv ou non.
for chemin in ${PATH//:/ }; do
# Remplacer VISUAL si nous trouvons nano.
[ -x "$chemin/nano" ] \
&& export VISUAL='nano --smooth --const --nowrap --suspend' && break
done
# Voir la note sur nano, pour les raisons d'employer une boucle.
for chemin in ${PATH//:/ }; do
# Alias vi pour vim en mode binaire, si possible.
[ -x "$chemin/vim" ] && alias vi='vim -b' && break
done
export EDITOR="$VISUAL"
# Une autre possibilit.
export SVN_EDITOR="$VISUAL" # Subversion.
alias edit=$VISUAL
# Commande utilisable sur tous les systmes.
# Fixer des options de ls et des alias. Le mcanisme des couleurs ne
# fonctionnera peut-tre pas, en fonction de votre mulateur de terminal
# et de sa configuration, en particulier la couleur ANSI. Cela ne doit
# pas crer de perturbation. Voir la note sur nano, pour les raisons
# d'employer une boucle.
for chemin in ${PATH//:/ }; do
[ -r "$chemin/dircolors" ] && eval "$(dircolors)" \
&& LS_OPTIONS='--color=auto' && break
done
export LS_OPTIONS="$LS_OPTIONS -F -h"
# Utiliser dircolors peut provoquer le dysfonctionnement des scripts
# csh et produire l'erreur "Unknown colorls variable `do'.". Le coupable
# est la partie ":do=01;35:" de la variable d'environnement LS_COLORS.
# La page http://forums.macosxhints.com/showthread.php?t=7287 propose
# une solution.
# eval "$(dircolors)"
alias ls="ls $LS_OPTIONS"
alias ll="ls $LS_OPTIONS -l"
alias ll.="ls $LS_OPTIONS -ld" # Usage : ll. ~/.*
alias la="ls $LS_OPTIONS -la"

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.20. Commencer une configuration personnalise

423

# Alias utiles.
alias bot='cd $(dirname $(find . | tail -1))'
alias clr='cd ~/ && clear' # Effacer l'cran et revenir $HOME.
alias cls='clear'
# Version DOS de clear.
alias copy='cp'
# Version DOS de cp.
#alias cp='cp -i'
# Option par dfaut pnible de Red Hat
# dfinie dans /root/.bashrc.
alias cvsst='cvs -qn update' # Pour obtenir un tat CVS concis
# (comme svn st).
alias del='rm'
# Version DOS de rm.
alias diff='diff -u'
# Par dfaut, des diffs unifis.
alias jdiff="diff --side-by-side --ignore-case --ignore-blank-lines\
--ignore-all-space --suppress-common-lines" # Commande GNU diff utile.
alias dir='ls'
# Version DOS de ls.
alias hr='history -a && history -n' # Ajouter la ligne en cours, puis
# relire l'historique.
alias ipconfig='ifconfig'
# Version Windows de ifconfig.
alias md='mkdir'
# Version DOS de mkdir.
alias move='mv'
# Version DOS de mv.
#alias mv='mv -i'
# Option par dfaut pnible de Red Hat
# dfinie dans /root/.bashrc.
alias ntsysv='rcconf'
# rcconf de Debian est presqu'identique
# ntsysv de Red Hat.
alias pathping='mtr'
# mtr - outil de diagnostic du rseau.
alias r='fc -s'
# Rappeler et excute une 'commande'
# qui commence par...
alias rd='rmdir'
# Version DOS de rmdir.
alias ren='mv'
# Version DOS de mv/rename.
#alias rm='rm -i'
# Option par dfaut pnible de Red Hat
# dfinie dans /root/.bashrc.
alias svnpropfix='svn propset svn:keywords "Id URL"'
alias tracert='traceroute' # Version DOS de traceroute.
alias vzip='unzip -lvM'
# Afficher le contenu d'un fichier ZIP.
alias wgetdir="wget --non-verbose --recursive --no-parent --no-directories\
--level=1"
# Obtenir un rpertoire entier avec wget.
alias zonex='host -l'
# Extraire une zone DNS.
# Si le script existe et est excutable, crer un alias pour
# obtenir des en-ttes de serveur web fiables.
for chemin in ${PATH//:/ }; do
[ -x "$chemin/lwp-request" ] && alias httpdinfo='lwp-request -eUd' &&
break
done
# Essayer kbdrate pour rendre le clavier plus rapide, mais ne rien
# dire s'il n'existe pas. Plus facile/plus rapide d'carter
# l'erreur si l'outil n'existe pas...
kbdrate -r 30.0 -d 250 &> /dev/null

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

424

Chapitre 16 Configurer bash

# Fonctions utiles.
# Crer un nouveau rpertoire (mkdir) et y aller (cd).
# Usage : mcd (<mode>) <rp>
function mcd {
local nouv_rep='_echec_de_mcd_'
if [ -d "$1" ]; then
# Le rpertoire existe, l'indiquer...
echo "$1 existe dj..."
nouv_rep="$1"
else
if [ -n "$2" ]; then
# Un mode a t indiqu.
command mkdir -p -m $1 "$2" && nouv_rep="$2"
else
# mkdir normal.
command mkdir -p "$1" && nouv_rep="$1"
fi
fi
builtin cd "$nouv_rep"
# Quel qu'il soit, aller dans
# le rpertoire.
} # Fin de mcd.

# Calculatrice simple en ligne de commande


function calculer {
# Uniquement avec des entiers ! --> echo La rponse est : $(( $* ))
# En virgule flottante.
awk "BEGIN {print \"La rponse est : \" $* }";
} # Fin de calculer.

# Autoriser l'emploi de 'cd ...' pour remonter de 2 niveaux,


# 'cd ....' pour remonter de 3 niveaux, etc. (comme 4NT/4DOS).
# Usage : cd ..., etc.
function cd {
local option= longueur= compte= chemin_cd= i= # Porte locale et init.
# Si l'option -L ou -P de lien symbolique est prsente, la
# mmoriser, puis la retirer de la lise.
if [ "$1" = "-P" -o "$1" = "-L" ]; then
option="$1"
shift
fi
# La syntaxe spciale est-elle utilise ? Vrifier que $1 n'est pas
# vide, puis examiner les 3 premiers caractres de $1 pour voir s'il
# s'agit de '...' et vrifier s'il n'y a pas de barre oblique en
# tentant une substitution ; si elle choue, il n'y en a pas. Ces
# deux oprations exigent bash 2.0+
if [ -n "$1" -a "${1:0:3}" = '...' -a "$1" = "${1%/*}" ]; then

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.20. Commencer une configuration personnalise

425

# La syntaxe spciale est utilise.


longueur=${#1} # Supposer que $1 contient uniquement des points
# et les compter.
compte=2
# 'cd ..' signifie toujours remonter d'un niveau,
# donc ignorer les deux premiers.
# Tant qu'il reste des points, remonter d'un niveau.
for ((i=$compte;i<=$longueur;i++)); do
chemin_cd="${chemin_cd}../" # Construire le chemin de cd.
done
# Effectuer le changement de rpertoire.
builtin cd $option "$chemin_cd"
elif [ -n "$1" ]; then
# La syntaxe spciale n'est pas utilise ; invoquer la commande
# cd normale.
builtin cd $option "$*"
else
# La syntaxe spciale n'est pas utilise ; invoquer la commande
# cd normale vers le rpertoire personnel.
builtin cd $option
fi
} # Fin de cd.
# Raliser des oprations propres au site ou la machine.
case $HOSTNAME in
*.societe.fr
) # source $CONFIGURATIONS/societe.fr
;;
hote1.*
) # contenu pour hote1.
;;
hote2.societe.fr ) # source .bashrc.hote2
;;
drake.*
) # echo DRAKE dans bash_profile.jp !
export TAPE=/dev/tape
;;
esac

Exemple de fichier inputrc :


# bash Le livre de recettes : inputrc
# configurations/inputrc : paramtres de readline
# Pour le relire (et utiliser les modifications de ce fichier) :
# bind -f $CONFIGURATIONS/inputrc
# Tout d'abord, inclure les liaisons et les affectations de
# variables de niveau systme provenant de /etc/inputrc
# (choue en silence si le fichier n'existe pas).
$include /etc/inputrc

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

426

Chapitre 16 Configurer bash

$if Bash
# Ignorer la casse lors de la compltion.
set completion-ignore-case on
# Ajouter une barre oblique aux noms de rpertoires complts.
set mark-directories on
# Ajouter une barre oblique aux noms complts qui sont des liens
# vers des rpertoires.
set mark-symlinked-directories on
# Utiliser ls -F pour la compltion.
set visible-stats on
# Parcourir les compltions ambigus au lieu d'afficher la liste.
"\C-i": menu-complete
# Activer la sonnerie.
set bell-style audible
# Lister les compltions possibles au lieu de faire retentir la
# sonnerie.
set show-all-if-ambiguous on
#
#
#
#

Extrait de la documentation de readline


http://tiswww.tis.case.edu/php/chet/readline/readline.html#SEC12
Les macros sont pratiques pour l'interaction avec le shell.
Modifier le chemin.
"\C-xp": "PATH=${PATH}\e\C-e\C-a\ef\C-f"
# Prparer la saisie d'un mot entre guillemets : insrer des
# guillemets ouvrants et fermants, puis se placer juste aprs les
# guillemets ouvrants.
"\C-x\"": "\"\"\C-b"
# Insrer une barre oblique inverse (test des chappements dans les
# squences et les macros).
"\C-x\\": "\\"
# Mettre entre guillemets le mot courant ou prcdent.
"\C-xq": "\eb\"\ef\""
# Ajouter une liaison pour rafficher la ligne.
"\C-xr": redraw-current-line
# Modifier la variable sur la ligne en cours.
#"\M-\C-v": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y="
"\C-xe": "\C-a\C-k$\C-y\M-\C-e\C-a\C-y="
$endif

Exemple de fichier bash_logout :


# bash Le livre de recettes : bash_logout
# configurations/bash_logout : excut la fermeture de session.
# Effacer l'cran afin d'viter les fuites d'informations, si ce
# n'est pas dj dfini dans un gestionnaire de signal ailleurs.
[ "$PS1" ] && clear

Exemple de fichier lancer_screen (pour screen de GNU, quil vous faudra peut-tre installer) :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

16.20. Commencer une configuration personnalise

427

#!/usr/bin/env bash
# bash Le livre de recettes : lancer_screen
# lancer_screen - script enveloppe conu pour tre excut depuis
# fichier "profile" et dmarrer screen l'ouverture de session
# avec un menu convivial.
# Contrles.
if [ "$TERM" == "screen" ]; then
printf "%b" "Selon \$TERM = '$TERM', nous utilisons dj" \
" screen.\nArrt...\n"
exit 1
elif [ "$USING_SCREEN" == "YES" ]; then
printf "%b" "Selon \$USING_SCREEN = '$USING_SCREEN', nous"
" utilisons dj screen.\nArrt...\n"
exit 1
fi
#
#
#
#
#
#

La variable "$USING_SCREEN" est utilise dans les rares cas o screen


ne fixe pas $TERM screen. Cela peut se produire lorsque 'screen'
n'est pas dans TERMCAP ou assimils, par exemple sur un systme
Solaris 9 que nous utilisons, mais que nous n'administrons pas. Sans
un mcanisme indiquant que nous sommes dans screen, ce script entre
dans une boucle sans fin.

# Ajouter les options Quitter et Nouveau la liste, puis voir les


# crans dj en excution. La liste utilise l'espace comme dlimiteur
# et nous voulons uniquements les sessions screen relles. Nous nous
# servons donc de awk pour les filtrer et retirons les tabulations de
# la sortie de 'screen -ls'.
ecrans_dispos="Quitter Nouveau $(screen -ls | awk '/\)$/ { print $1$2$3 }' \
| tr -d ' ')"
# Afficher un avertissement en cas d'utilisation du retour l'excution.
retour_execution=0
[ "$retour_execution" == 1 ] && printf "%b" "
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'screen' Notes :
1) Si vous vous connectez un systme dj attach, vous 'volez'
cet cran existant.
2) Une session marque 'multi' se trouve en mode multi-utilisateurs.
Faites attention en cas de nouvel attachement.
3) Les sessions marques 'unreachable' ou 'dead' doivent tre identifies
et supprimes avec l'option -wipe, si ncessaire.\n\n"

# Prsenter une liste de choix.


PS3='Choisissez un cran pour cette session : '

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

428

Chapitre 16 Configurer bash

select selection in $ecrans_dispos; do


if [ "$selection" == "Quitter" ]; then
break
elif [ "$selection" == "Nouveau" ]; then
export USING_SCREEN=YES
exec screen -c $CONFIGURATIONS/screenrc -a \
-S $USER.$(date '+%Y-%m-%d_%H:%M:%S%z')
break
elif [ "$selection" ]; then
# Extraitre la partie utile l'aide de cut. Nous devrions
# employer une 'chane here' [$(cut -d'(' -f1 <<< $selection)]
# la place de echo, mais cela ne fonction qu'avec bash-2.05b+.
ecran_choisi=$(echo $selection | cut -d'(' -f1)
exec screen -dr $ecran_choisi
break
else
printf "%b" "Slection invalide.\n"
fi
done

Discussion
Consultez le code et les commentaires pour plus de dtails.
Il se passe une chose intressante lorsque vous fixez $PS1 des moments inadapts ou
si vous dfinissez des gestionnaires de signaux qui utilisent clear. De nombreux utilisateurs se servent du code suivant pour vrifier si le shell en cours est en mode interactif :
if [ "$PS1" ]; then
: Code pour le mode interactif.
fi

Si vous dfinissez $PS1 alors que le shell nest pas en mode interactif ou si vous crez un
gestionnaire de signal qui invoque uniquement clear et non [ "$PS1" ] && clear, vous
obtiendrez des erreurs telles que les suivantes avec scp ou ssh en mode non interactif :
# Pour tput :
No value for $TERM and no -T specified
# Pour clear :
TERM environment variable not set.

Voir aussi

les chapitres 17 19 ;

la recette 16.18, Utiliser correctement les fichiers dinitialisation, page 411 ;

la recette 16.19, Crer des fichiers dinitialisation autonomes et portables, page 414 ;

la recette 17.5, Partager une unique session bash, page 435 ;

lannexe C, Analyse de la ligne de commande, page 569.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17
Maintenance et tches
administratives
Les recettes de ce chapitre couvrent des tches qui interviennent au cours de lutilisation
ou de ladministration des ordinateurs. Elles sont regroupes ici car elles ne correspondent aucun autre chapitre de ce livre.

17.1. Renommer plusieurs fichiers


Problme
Vous voulez renommer, soit plusieurs fichiers, mais mv *.foo *.bar ne fonctionne pas,
soit tout un groupe de fichiers dune faon totalement arbitraire.

Solution
Nous avons prsent une boucle simple pour modifier les extensions de fichiers dans la
recette 5.18, page 109, consultez-la pour plus de dtails. Voici un exemple de boucle
for1 :
for FN in *.mauvais
do
mv "${FN}" "${FN%mauvais}bash"
done

Quen est-il des modifications encore plus arbitraires ? Par exemple, supposons que vous
soyez en train dcrire un livre, que vous vouliez que les noms de fichiers des diffrents
chapitres suivent un format particulier, mais que lditeur utilise un autre format. Vous
pourriez nommer les fichiers ainsi chNN=Titre=Auteur.odt, puis utiliser une simple boucle for et la commande cut pour renommer les fichiers :
$ for i in *.odt; do mv "$i" "$(echo $i | cut -d'=' -f1,3)"; done
1. N.d.T. : Cette boucle renomme tous les fichiers dont le nom se termine par .mauvais en
retirant la chane mauvais se trouvant la fin du nom et en ajoutant la chane bash .
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

430

Chapitre 17 Maintenance et tches administratives

Discussion
Vous devriez toujours entourer dapostrophes les noms de fichiers passs en argument
au cas o ils comporteraient des espaces. En testant le code, nous avons aussi utilis la
commande echo et les caractres infrieur/suprieur pour afficher clairement la valeur
des arguments (set -x peut aussi tre dune grande aide).
Une fois que nous tions certain que notre commande fonctionnait, nous avons retir
les caractres infrieur/suprieur et remplac echo par mv.
# Test
$ for i in *.odt; do echo "<$i>" "<$(echo $i | cut -d'=' -f1,3)>"; done
<ch01=Dbuter en shell=JP.odt> <ch01=JP.odt>
<ch02=Sortie standard=CA.odt> <ch02=CA.odt>
<ch03=Entre standard=CA.odt> <ch03=CA.odt>
<ch04=Excuter des commandes=CA.odt> <ch04=CA.odt>
[...]
# Pour tester encore plus
$ set -x
$ for i in *.odt; do echo "<$i>" "<$(echo $i | cut -d'=' -f1,3)>"; done
++xtrace 1: echo ch01=Dbuter en shell=JP.odt
++xtrace 1: cut -d= -f1,3
+xtrace 535: echo '<ch01=Dbuter en shell=JP.odt>' '<ch01=JP.odt>'
<ch01=Dbuter en shell=JP.odt> <ch01=JP.odt>
++xtrace 1: echo ch02=Sortie standard=CA.odt
++xtrace 1: cut -d= -f1,3
+xtrace 535: echo '<ch02=Sortie standard=CA.odt>' '<ch02=CA.odt>'
<ch02=Sortie standard=CA.odt> <ch02=CA.odt>
++xtrace 1: echo ch03=Entre standard=CA.odt
++xtrace 1: cut -d= -f1,3
+xtrace 535: echo '<ch03=Entre standard=CA.odt>' '<ch03=CA.odt>'
<ch03=Entre standard=CA.odt> <ch03=CA.odt>
++xtrace 1: echo ch04=Excuter des commandes=CA.odt
++xtrace 1: cut -d= -f1,3
+xtrace 535: echo '<ch04=Excuter des commandes=CA.odt>' '<ch04=CA.odt>'
<ch04=Excuter des commandes=CA.odt> <ch04=CA.odt>
$ set +x
+xtrace 536: set +x

Nous avons ce type de boucles for ailleurs dans ce livre car elles sont bien utiles. La difficult tient passer les bonnes valeurs en argument mv, cp ou nimporte quelle
autre commande. Dans ce cas, nous avons utilis le caractre = comme dlimiteur et
tout ce qui nous intressait tait le premier champ, la solution tait facile...
Pour dterminer les valeurs dont vous avez besoin, utilisez la commande ls (ou find)
pour lister les fichiers sur lesquels vous travaillez et pour les transmettre la chane
doutils voulue, souvent cut, awk ou sed. Lvaluation des paramtres de bash (recette
5.18, page 109) est galement trs utile ici :
$ ls *.odt | cut -d'=' -f1
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.2. Utiliser GNU Texinfo et Info sous Linux

431

Avec un peu de chance, une recette de ce livre vous donnera les dtails ncessaires pour
obtenir les valeurs souhaites placer en argument, il ne restera plus qu assembler les
diffrentes pices. Pensez bien commencer par tester la commande avec echo et chercher les caractres spciaux et les espaces dans les noms de fichier.
Nappelez pas votre script rename. Nous avons connaissance dau moins
deux commandes rename diffrentes dans les distributions majeures de
Linux et il y en a certainement de nombreuses autres. Le paquetage
util-linux de Red Hat propose un outil rename chane_origine
chane_destination nom_de_fichier. Debian et ses drivs incluent
une commande rename base sur Perl de Larry Wall dans les paquetages Perl et disposent dun paquetage renameutils associ. Solaris, HP-UX
et certains systmes BSD documentent un appel systme rename, mais
il nest pas facilement accessible pour un utilisateur. Demandez la page
de manuel rename sur votre systme pour voir ce que vous obtenez.

Voir aussi

man mv ;

man rename ;

help for ;

la recette 5.18, Modifier certaines parties dune chane, page 109 ;

la recette 9.2, Traiter les noms de fichiers contenant des caractres tranges, page 193 ;

la recette 17.12, Effacer ou renommer des fichiers dont le nom comporte des caractres
spciaux, page 448 ;

la recette 19.13, Dboguer des scripts, page 500.

17.2. Utiliser GNU Texinfo et Info sous Linux


Problme
Vous rencontrez des difficults pour accder la documentation car la plupart des outils
GNU sous Linux la fournissent dans le format Texinfo. Les pages de manuel traditionnelles ne sont que des renvois vers cette documentation. Le programme info nest pas
convivial et vous ne voulez pas apprendre utiliser un autre programme pour un usage
unique.

Solution
Redirigez la commande info dans un afficheur pratique tel que less.
$ info bash | less

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

432

Chapitre 17 Maintenance et tches administratives

Discussion
info est essentiellement une version autonome du lecteur de document info dEmacs, si
vous tes un fan dEmacs, son utilisation a peut-tre un sens pour vous. Cependant, rediriger laffichage dans less est un moyen rapide et simple pour consulter la documentation laide dun outil familier.
Lide sous-jacente Texinfo est bonne : gnrer diffrents formats de documentation
partir dune source unique. Ce nest pas nouveau, de nombreux autres langages balises
existent dans le mme but ; nous avons mme cit lun dentre-eux dans la recette 5.2,
page 88. Mais si cest le cas, pourquoi nexiste-t-il pas de filtre de sortie TeX vers man ?
Peut-tre parce que les pages de manuel suivent un format standard, structur et longuement test alors que TeXinfo est beaucoup plus libral.
Si vous naimez pas info, il existe dautres afficheurs et convertisseurs Texinfo tels que
pinfo, info2www, tkman ou mme info2man (qui triche et utilise un format intermdiaire, POD, pour obtenir le format du manuel).

Voir aussi

man info ;

man man ;

http://en.wikipedia.org/wiki/Texinfo ;

la recette 5.2, Incorporer la documentation dans les scripts, page 88.

17.3. Dzipper plusieurs archives ZIP


Problme
Vous voulez dcompresser plusieurs fichiers ZIP dans un rpertoire, mais unzip *.zip
ne fonctionne pas.

Solution
Placez le motif entre apostrophes :
unzip '*.zip'

Vous pouvez aussi utiliser une boucle pour dcompresser chaque archive :
for x in /chemin/vers/date*/nom/*.zip; do unzip "$x"; done

ou :
for x in $(ls /chemin/vers/date*/nom/*.zip 2>/dev/null); do unzip $x; done

Discussion
Contrairement de nombreuses commandes Unix (telles que gzip et bzip2), le dernier
argument de unzip nest pas une liste de noms de fichier de longueur arbitraire. Pour

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.4. Restaurer des sessions dconnectes avec screen

433

excuter la commande unzip *.zip, le shell value le caractre joker et (en supposant
que vous avez des fichiers nomms de fichierzip1.zip fichierzip4.zip) unzip *.zip sera
interprt comme unzip fichierzip1.zip fichierzip2.zip
fichierzip3.zip
fichierzip4.zip. Cette commande tente dextraire les fichiers fichierzip2.zip,
fichierzip3.zip et fichierzip4.zip partir de larchive fichierzip1.zip. Elle va donc chouer
moins que fichierzip1.zip ne contienne effectivement des fichiers nomms ainsi.
La premire mthode interdit linterprteur de commande dvaluer le joker laide
dapostrophes. Cependant, cela ne fonctionne que sil ny a quun seul caractre joker.
Les seconde et troisime mthodes contournent ce problme en excutant explicitement une commande unzip pour chaque fichier ZIP trouv avec lvaluation des jokers
par le shell ou dans le rsultat de la commande ls.
La version avec ls est utilise car, par dfaut, bash (et sh) retourne les motifs tels quils
sont, sans interprtation possible. Cela signifie que vous tenteriez de dcompresser un
fichier appel /chemin/vers/date*/nom/*.zip dans le cas o aucune correspondance nest
trouve. ls retournera un rsultat vide sur la sortie standard et une erreur que nous ignorerons sur la sortie derreur standard. Vous pouvez utiliser shopt -s nullglob pour que
les motifs sans correspondance soient remplacs par une chane vide plutt que par euxmmes.

Voir aussi

man unzip ;

http://www.info-zip.org/pub/infozip ;

la recette 15.13, Contourner les erreurs liste darguments trop longue , page 357.

17.4. Restaurer des sessions dconnectes avec


screen
Problme
Vous excutez de longs traitements travers des connexions SSH, parfois travers un
rseau, et vous perdez tout votre travail lorsque vous tes dconnect. Il vous arrive de
commencer une tche longue depuis votre lieu de travail, mais vous devez rentrer chez
vous et continuer plus tard. Vous pourriez lancer les commandes en utilisant nohup,
mais vous ne pourrez pas rattacher votre terminal au processus lorsque la connexion
sera rtablie ou lorsque vous serez chez vous.

Solution
Installez et utilisez GNU screen.
Lutilisation de screen est trs simple. Tapez screen ou screen -a. Loption -a inclut toutes les fonctionnalits de screen mme si elles consomment plus de ressources. Pour tre
franc, nous utilisons loption -a mais navons jamais remarqu la moindre diffrence.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

434

Chapitre 17 Maintenance et tches administratives

Lorsque vous faites cela, tout se passera comme si vous naviez rien fait, mais vous tes
maintenant dans un processus screen. echo $SHLVL devrait renvoyer un nombre plus
lev (consultez L$SHLVL la recette 16.2, page 368). Pour tester, faites un ls -la puis un
kill dans votre terminal (ne le quittez pas classiquement, vous termineriez aussi lexcution de screen). Reconnectez-vous sur la machine et tapez screen -r pour vous reconnecter screen. Si cela ne vous ramne pas lcran que vous avez quitt, essayez screen
-d -r. Si cela ne fonctionne pas, tapez ps auwx | grep [s]creen pour voir si screen continue de sexcuter, puis regardez laide la rsolution des problmes dans la page de
manuel laide de man screen, mais cela devrait fonctionner. Si vous rencontrez des problmes avec cette commande ps sous un autre systme que Linux, consultez la recette
17.19, page 464.
En dmarrant screen avec une commande comme celle-ci, il sera plus simple de savoir
quelle session vous attacher plus tard : screen -aS "$(whoami).$(date '+%Y-%m-%d_
%H:%M:%S%z')". Consultez le script lancer_screen de la recette 16.20, page 416.
Pour quitter screen et votre session, tapez exit jusqu ce que toutes vos sessions soient
fermes. Vous pouvez aussi taper Ctrl-A Ctrl-\ ou Ctrl-A :quit pour quitter screen luimme (en supposant que vous navez pas encore modifi la configuration de la touche
Meta).

Discussion
Selon le site de screen :
Screen est un gestionnaire de fentres plein cran qui multiplexe plusieurs processus
sur un seul terminal (habituellement des interprteurs de commandes interactifs)
physique. Chaque terminal virtuel offre les possibilits dun terminal DEC VT100
plus certaines fonctions des standards ISO 6429 (ECMA 48, ANSI X3.64) et ISO 2022
(comme linsertion/suppression de ligne et le support de plusieurs jeux de caractres). Chaque terminal dispose dun tampon dfilant pour chaque terminal virtuel et
dun mcanisme de copier-coller qui permet de dplacer des rgions de texte entre les
fentres.

Cela signifie que vous pouvez avoir plus dune session dans un unique terminal SSH
(rappelez-vous DeskView sur les i286/386). Mais cela vous permet aussi de vous connecter par SSH sur une machine, de dmarrer un processus, de vous dconnecter et de rentrer chez vous pour vous reconnecter et de reprendre votre travail, non pas l o vous
en tiez, mais l o en est le processus qui a continu de sexcuter. screen permet plusieurs personnes de partager une unique session pour sentraner, rsoudre des problmes ou travailler en collaboration (consulter la recette 17.5, page 435).

Mise en garde
screen est souvent install par dfaut sous Linux, mais rarement sous dautres systmes.
Le binaire screen doit disposer du bit SUID et appartenir lutilisateur root pour pouvoir crire dans le pseudo terminal (tty) usr/dev appropri. Si screen ne fonctionne pas,
il est possible que les permissions soient en cause (pour les corriger, entrez chmod u+s
/usr/bin/screen en tant que root).
screen interfre avec les protocoles de transfert en-ligne tels que zmodem. Les dernires versions de screen disposent de rglages de configuration pour grer ce problme ;
consultez les pages de manuel pour en savoir plus ce sujet.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.5. Partager une unique session bash

435

Configuration
Le mode ddition Emacs par dfaut de la ligne de commande bash utilise Ctrl-A
pour aller au dbut de la ligne. screen a le mme mode de commande mais peut aussi
utiliser la touche meta si vous utilisez dj beaucoup Ctrl-A, comme nous le faisons.
Pour cela, ajoutez les lignes suivantes votre fichier ~/.screenrc :
#
#
#
#

Rglages d'exemple pour ~/.screenrc


Changer la combinaison par dfaut C-a
en C-n (utilise C-n n pour envoyer un
vrai caractre ^N)
escape ^Nn
# La cloche systme est mieux qu'un
# clignotement
vbell off
# Dtacher la session en cas de coupure
# de connexion
autodetach on
# Utiliser un interprteur de commande de
# connexion dans chaque fentre
shell -$SHELL

Voir aussi

man screen ;

http://www.gnu.org/software/screen ;

http://en.wikipedia.org/wiki/GNU_Screen ;

http://jmcpherson.org/screen.html ;

http://aperiodic.net/screen ;

la recette 16.2, Personnaliser linvite, page 368 ;

la recette 16.20, Commencer une configuration personnalise, page 416 ;

la recette 17.5, Partager une unique session bash, page 435 ;

la recette 17.6, Enregistrer une session complte ou un traitement par lots, page 437 ;

la recette 17.9, Indexer de nombreux fichiers, page 440 ;

la recette 17.18, Filtrer la sortie de ps sans afficher le processus grep, page 463.

17.5. Partager une unique session bash


Problme
Vous avez besoin de partager une unique session bash dans un but de formation ou de
recherche de panne, mais il nest pas possible que toutes les personnes intresses puis-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

436

Chapitre 17 Maintenance et tches administratives

sent regarder votre moniteur par dessus votre paule, ou vous avez besoin daider une
autre personne situe ailleurs en partageant une session avec elle travers le rseau.

Solution
Utilisez GNU screen en mode multi-utilisateurs. La suite de ce chapitre suppose que
vous navez pas modifi le paramtrage par dfaut de la touche meta (Ctrl-A), comme
indiqu dans la partie configuration de la recette 17.4, page 433. Si vous lavez dj fait,
utilisez votre nouvelle touche meta (Ctrl-N, par exemple).
1. En tant que formateur, effectuez les tches suivantes : screen -S nom_de_session
(les espaces sont interdites) ; exemple : screen -S formation.
2. Ctrl-A :addacl identifiants des comptes utilisateurs (sans espace et spars par des
virgules) qui doivent pouvoir accder laffichage ; exemple : Ctrl-A :addacl
alice,bob,carole. Cela permet un accs complet en lecture et en criture.
3. Au besoin, utilisez la commande Ctrl-A :chacl identifiants bits_perm liste
pour affiner les permissions.
4. Activez le mode multi-utilisateurs : Ctrl-A :multiuser on.
En tant que spectateur, effectuez les tches suivantes :
1. Utilisez screen -x identifiant/session pour vous connecter un affichage partag ; exemple : screen -x bob/formation.
2. Tapez Ctrl-A K pour tuer la fentre et terminer la session.

Discussion
Consultez la recette 17.4, page 433, pour plus de dtails.
Pour le mode multi-utilisateurs, /tmp/screens doit exister, tre accessible en lecture pour
tout le monde et tre excutable.
Les versions RedHat (RHEL3 par exemple) de la 3.9.15-8 la 4.0.1-1 de screen sont dfectueuses et ne doivent pas tre utilises si vous voulez la fonctionnalit multi-utilisateurs. La version 4.0.2-5 et les suivantes devraient fonctionner, par exemple,
http://mirror.centos.org/centos/4.2/os/i386/CentOS/RPMS/screen-4.0.2-5. i386.rpm (ou ultrieures) fonctionnent mme sous RHEL3. Une fois que vous avez commenc utiliser
la nouvelle version de screen, les sockets screen existant dans le rpertoire $HOME/.screen
ne sont plus utilisables. Dconnectez-vous de toutes les sessions et utilisez la nouvelle
version pour crer de nouvelles sockets dans /tmp/screens/S-$USER, puis supprimez le rpertoire $HOME/.screen .

Voir aussi

man screen ;

http://www.gnu.org/software/screen ;

la recette 9.11, Retrouver un fichier partir dune liste demplacements possibles, page
202 ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.6. Enregistrer une session complte ou un traitement par lots

la recette 16.20, Commencer une configuration personnalise, page 416 ;

la recette 17.4, Restaurer des sessions dconnectes avec screen, page 433 ;

la recette 17.6, Enregistrer une session complte ou un traitement par lots, page 437.

437

17.6. Enregistrer une session complte ou un


traitement par lots
Problme
Vous avez besoin de capturer laffichage dune session complte ou dun long traitement.

Solution
Plusieurs solutions peuvent rsoudre ce problme, selon vos besoins et votre environnement.
La plus simple consiste activer la journalisation en mmoire ou sur disque dans votre
programme dmulation de terminal. Tous les mulateurs ne disposent pas de cette
fonctionnalit et, pour ceux qui en disposent, la journalisation sarrte lors de votre dconnexion.
La seconde solution est de modifier le traitement pour quil journalise lui-mme ce quil
fait, de tout rediriger vers tee ou vers un fichier. Par exemple, lune des lignes suivantes
pourrait convenir :
$ long_traitement >& fichier_trace
$ long_traitement 2>&1 | tee fichier_trace
$ ( long_traitement ) >& fichier_trace
$ ( long_traitement ) 2>&1 | tee fichier_trace

Ici, les problmes sont que vous ne pouvez pas forcment modifier le traitement ou que
ce dernier effectue des tches qui interdisent ces modifications (il peut avoir besoin
dune saisie interactive, par exemple). Cela peut se produire car la sortie standard est
mise dans une mmoire tampon, linvite peut se trouver dans le tampon en attente
dtre affiche alors que dautres donnes continuent darriver, mais aucune donne ne
sera traite par le programme car il attend une saisie.
Il existe un programme intressant appel script conu pour traiter ce cas prcis et il est
certainement dj install sur votre systme. Vous excutez script et il enregistrera tout
ce qui se produira dans le fichier journal (appel un typescript) que vous lui aurez indiqu. Si vous souhaitez enregistrer une session complte, lancez script, puis votre traitement. Mais si vous ne voulez capturer quune partie de la session, il nexiste pas de
solution pour que votre code excute script, effectue les tches journaliser et stoppe
script. Vous ne pouvez pas scripter script car, lorsque vous lexcutez, il ouvre un sousshell (cest--dire que vous ne pouvez pas faire script fichier_trace commande).
Notre dernire solution est dutiliser le multiplexeur de terminal screen. Avec screen,
vous pouvez activer et dsactiver les fonctionnalits de journalisation depuis votre

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

438

Chapitre 17 Maintenance et tches administratives

script. Lorsque vous vous trouvez dans une session screen, ajoutez les lignes suivantes
dans votre script :
# Configuration d'un fichier de trace et
# activation de la journalisation
screen -X fichier_journal /chemin/vers/le/fichier && screen -X log on
# vos commandes
# Dsactivation de la journalisation
screen -X log off

Discussion
Nous vous recommandons dessayer les solutions dans cet ordre et dutiliser la premire
qui rpond votre besoin. A moins que vous ayiez des besoins trs particuliers, script
fonctionnera certainement. Mais, dans lhypothse o il ne suffirait pas, il peut tre intressant de connatre les options de screen.

Voir aussi

man script ;

man screen ;

la recette 17.5, Partager une unique session bash, page 435.

17.7. Effacer lcran lorsque vous vous


dconnectez
Problme
Vous utilisez ou administrez certains systmes neffaant pas laffichage lors de la dconnexion et vous prfreriez ne pas laisser les dernires commandes tapes et leurs rsultats lcran ; cela pourrait entraner des fuites dinformations.

Solution
Placez la commande clear dans votre fichier ~/.bash_logout :
# ~/.bash_logout
#
#
#
#
[

Effacer l'cran la fin d'une session pour


viter les fuites d'informations si ce n'est
pas dj configur grce une capture de
signal dans bash_profile
"$PS1" ] && clear

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.8. Capturer les mta-informations des fichiers pour une restauration

439

Ou configurez une interception de signal pour excuter clear la fin dun shell :
# ~/.bash_profile
# Interception de signal pour effacer l'cran
# la sortie d'un shell et viter les fuites
# d'informations, si ce n'est pas dj
# configur dans ~/.bash_logout
trap ' [ "$PS1" ] && clear ' 0

Remarquez que si vous vous connectez distance et que votre client dispose dun tampon de dfilement, tout ce sur quoi vous avez travaill peut encore sy trouver. clear na
aucun effet non plus sur lhistorique des commandes gr par linterprteur de commandes.

Discussion
Configurer une interception de signal pour effacer lcran est certainement disproportionn, mais cela permet de traiter le cas o une erreur empche ~/.bash_logout de sexcuter. Si vous tes vraiment paranoaque, vous pouvez configurer les deux solutions
mais, dans ce cas, vous devriez aussi vous intresser TEMPEST et aux cages de Faraday.
Si vous ne testez pas si linterprteur a t lanc en mode interactif ou non, vous risquez
de rencontrer des erreurs similaires celles-ci :
# partir de tput, par exemple
No value for $TERM and no -T specified
# partir de clear, par exemple
TERM environment variable not set.

Voir aussi

http://en.wikipedia.org/wiki/TEMPEST ;

http://fr.wikipedia.org/wiki/TEMPEST ;

http://fr.wikipedia.org/wiki/Cage_de_Faraday ;

http://en.wikipedia.org/wiki/Faraday_cag ;

la recette 16.20, Commencer une configuration personnalise, page 416.

17.8. Capturer les mta-informations des


fichiers pour une restauration
Problme
Vous voulez crer une liste des fichiers et des dtails les concernants dans un but de sauvegarde, que ce soit pour vrifier les sauvegardes, recrer des rpertoires, etc. Ou vous
tes peut-tre sur le point dexcuter un grand chmod -R et vous avez besoin dune mthode dannulation des modifications. Ou enfin, vous conservez le contenu du rpertoire /etc/* dans un systme de gestion de versions qui ne garde pas la trace des droits daccs
ou des propritaires.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

440

Chapitre 17 Maintenance et tches administratives

Solution
Utilisez GNU find avec largument printf :
#!/usr/bin/env bash
# bash Le livre de recettes : archive_meta-data
printf "%b" "Mode\tUtilisateur\tGroupe\tOctets\tModifi\tFichier\n" >
fichier_archive
find / \( -path /proc -o -path /mnt -o -path /tmp -o -path /var/tmp \
-o -path /var/cache -o -path /var/spool \) -prune \
-o -type d -printf 'd%m\t%u\t%g\t%s\t%t\t%p/\n' \
-o -type l -printf 'l%m\t%u\t%g\t%s\t%t\t%p -> %l\n' \
-o
-printf '%m\t%u\t%g\t%s\t%t\t%p\n' \) >> fichier_archive
Notez que lexpression -printf appartient la version GNU de find.

Discussion
La partie (-path /foo -o -path ...) -prune retire diffrents rpertoires dont vous ne
vous souciez certainement pas, -type d prcise de ne soccuper que des rpertoires. Le
format printf est prfix avec un d, puis utilise le mode daccs, lutilisateur, le groupe,
etc. Loption -type l correspond aux liens symboliques et indique aussi la cible des liens.
Avec le contenu de ce fichier et un script supplmentaire, vous pouvez dterminer si
une information a t change ou recrer les appartenances et les permissions
modifies. Remarquez que cette technique ne se substitue pas lutilisation de programmes spcialiss dans la scurit, tels que Tripwire, AIDE, Osiris ou Samhain.

Voir aussi

man find ;

le chapitre 9, Rechercher des fichiers avec find, locate et slocate, page 191 ;

http://www.tripwiresecurity.com ;

http://sourceforge.net/projects/aide ;

http://osiris.shmoo.com ;

http://la-samhna.de/samhain/index.html.

17.9. Indexer de nombreux fichiers


Problme
Vous disposez de nombreux fichiers pour lesquels vous aimeriez avoir un index.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.10. Utiliser diff et patch

441

Solution
Utilisez la commande find associe head, grep ou dautres outils pouvant parcourir
les commentaires ou les rsums de chaque fichier.
Par exemple, si la seconde ligne de tous vos scripts respecte le format nom
description , voici une possibilit pour crer un index :
$ for i in $(grep -El '#![[:space:]]?/bin/sh' *); do head -2 $i | tail -1;
done

Discussion
Comme indiqu, cette technique sappuie sur la prsence dinformations dans chaque
fichier, comme des commentaires, qui peuvent tre parcourues. Nous cherchons ensuite un moyen didentifier le type de fichier, un script shell dans notre exemple, et en extrayons la seconde ligne.
Si les fichiers ne disposent pas dun rsum facilement accessible, vous pouvez essayer
cette solution et retravailler manuellement le rsultat pour en faire un index :
for dir in $(find . -type d); do head -15 $dir/*; done
Prenez garde aux fichiers binaires !

Voir aussi

man find ;

man grep ;

man head ;

man tail.

17.10. Utiliser diff et patch


Problme
Vous narrivez jamais vous rappeler comment utiliser diff pour crer des correctifs
pouvant tre appliqus grce patch2.

2. N.d.T. : Vous avez modifi certains fichiers dun gros projet et aimeriez partager vos modifications sans devoir diffuser nouveau la totalit des fichiers du projet.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

442

Chapitre 17 Maintenance et tches administratives

Solution
Si vous voulez crer un simple correctif pour un unique fichier, utilisez3 :
$ diff -u fichier_original fichier_modifie > fichier_correctif

Si vous voulez crer un correctif pour plusieurs fichiers dune arborescence, utilisez :
$ cp -pR repertoire_original/ repertoire_modifie/
# Faites vos modifications dans la copie
$ diff -Nru repertoire_original/ repertoire_modifie/ > correctif_complet

Pour tre vraiment prudent, forcez diff interprter tous les fichiers comme tant des
fichiers texte ASCII laide de loption -a et configurez la langue et le fuseau horaire
par dfaut comme ceci :
$ LC_ALL=C TZ=UTC diff -aNru repertoire_original/ repertoire_modifie/ >
correctif_complet
$ LC_ALL=C TZ=UTC diff -aNru repertoire_original/ repertoire_modifie/
diff -aNru repertoire_original/fichier_modifie
repertoire_modifie/fichier_modifie
--- repertoire_original/fichier_modifie 2006-11-23 01:04:07.000000000 +0000
+++ repertoire_modifie/fichier_modifie 2006-11-23 01:04:35.000000000 +0000
@@ -1,2 +1,2 @@
Ce fichier est commun aux deux rpertoires.
-Mais ses deux versions diffrent.
+Mais ses 2 versions diffrent.
diff -aNru repertoire_original/dans_cible_seulement
repertoire_modifie/dans_cible_seulement
--- repertoire_original/dans_cible_seulement 1970-01-01 00:00:00.000000000
+0000
+++ repertoire_modifie/dans_cible_seulement 2006-11-23 01:05:58.000000000
+0000
@@ -0,0 +1,2 @@
+Ce fichier n'est que dans le rpertoire modifi.
+Il comporte aussi deux lignes dont c'est la dernire.
diff -aNru repertoire_original/dans_origine_seulement
repertoire_modifie/dans_origine_seulement
--- repertoire_original/dans_origine_seulement 2006-11-23
01:05:18.000000000 +0000
+++ repertoire_modifie/dans_origine_seulement 1970-01-01 00:00:00.000000000
+0000

3. N.d.T. : La coutume veut que les fichiers correctifs ainsi gnrs portent lextension .diff ou
.patch. De mme, la base de leur nom contient en gnral le numro de la version originale, le
numro de la version modifie et, ventuellement, la raison du correctif en quelques mots. Cela
permet de savoir sur quelle version des fichiers peut sappliquer le correctif sans gnrer derreurs
et dans quelle version seront les fichiers aprs lapplication du correctif, pour pouvoir enchaner
dautres correctifs.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.10. Utiliser diff et patch

443

@@ -1,2 +0,0 @@
-Ce fichier n'est que dans le rpertoire d'origine.
-Il comporte deux ligne dont celle-ci est la dernire.

Pour appliquer un fichier de correctif, placez-vous dans le rpertoire du fichier corriger ou dans la racine de larborescence et utilisez la commande patch :
cd /chemin/vers/les/fichiers
patch -Np1 < correctif

Largument -N de patch lui interdit dinverser le correctif ou de lappliquer un fichier


dj corrig. Loption -p nombre retire nombre rpertoires du dbut du chemin pour permettre lapplication des correctifs dans une arborescence qui ne serait pas exactement
identique celle ayant servi la gnration du correctif. En gnral, lutilisation de -p1
fonctionnera ; dans le cas contraire, essayez avec -p0, puis -p2, etc. Soit cela fonctionnera, soit loutil vous demandera ce quil doit faire. Auquel cas vous annulerez et essayerez
une autre possibilit, moins de bien savoir ce que vous faites.

Discussion
diff peut produire un rsultat sous diffrents formats, certains sont plus utiles que
dautres. Le format unifi, obtenu avec loption -u, est gnralement considr comme
tant le meilleur car il est la fois raisonnablement lisible par un tre humain et trs
robuste lorsquil est appliqu avec patch. Il fournit trois lignes de contexte autour des
changements, ce qui permet un lecteur humain de se reprer et la commande patch
de fonctionner correctement, mme si le fichier corriger est diffrent du fichier original ayant servi construire le correctif 4. Tant que les lignes de contexte nont pas t
modifie, patch peut habituellement les retrouver5. Laffichage du contexte, en utilisant
-c, est similaire laffichage obtenu avec -u, mais il est redondant et moins facile lire.
Le format ed, obtenu avec loption -e, produit un script utilisable avec lancien diteur
ed. Enfin, laffichage par dfaut se rapproche du format ed, avec un contexte un peu plus
lisible pour un tre humain.
# Format unifi (prfer)
$ diff -u fichier_original fichier_modifi
--- fichier_original
2006-11-22 19:29:07.000000000 -0500
+++ fichier_modifi
2006-11-22 19:29:47.000000000 -0500
@@ -1,9 +1,9 @@
-Ligne diffrente du fichier original
+Ligne diffrente du fichier modifi
Cette ligne est identique.
Tout comme celle-ci.
Et celle-l.
Ditto.
-Mais cette ligne est diffrente.
+Mais celle-ci est diffrente.

4. N.d.T. : Dans une certaine mesure, bien sr.


5. N.d.T. : Il tolre par dfaut un dcalage de deux lignes, pour plus dinformations consultez la
page de manuel de patch sur loption -F ou --fuzz.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

444

Chapitre 17 Maintenance et tches administratives


Contrairement cette ligne.
Et cette dernire ligne est identique.

# Format contextuel
$ diff -c fichier_original fichier_modifi
*** fichier_original
Wed Nov 22 19:29:07 2006
--- fichier_modifi
Wed Nov 22 19:29:47 2006
***************
*** 1,9 ****
! Ligne diffrente du fichier original
Cette ligne est identique.
Tout comme celle-ci.
Et celle-l.
Ditto.
! Mais cette ligne est diffrente.
Contrairement cette ligne.
Et cette dernire ligne est identique.
--- 1,9 ---! Ligne diffrente du fichier modifi
Cette ligne est identique.
Tout comme celle-ci.
Et celle-l.
Ditto.
! Mais celle-ci est diffrente.
Contrairement
# Format 'ed'
$ diff -e fichier_original fichier_modifi
6c
Mais celle-ci est diffrente.
.
1c
Ligne diffrente du fichier modifi
.

# Format normal
$ diff fichier_original fichier_modifi
1c1
< Ligne diffrente du fichier original
--> Ligne diffrente du fichier modifi
6c6
< Mais cette ligne est diffrente.
--> Mais celle-ci est diffrente.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.10. Utiliser diff et patch

445

Les arguments -r et -N de diff sont simples mais puissants. -r signifie, comme dhabitude, que lopration doit tre rcursive dans larborescence, alors que -N force diff considrer que tout fichier trouv uniquement dans une arborescence existe aussi dans
lautre, sous la forme dun fichier vide. En thorie, cela permet aussi de crer ou de supprimer des fichiers. Cependant, dans la pratique, -N nest pas prise en charge sur tous les
systmes (notamment Solaris) et elle peut entraner la cration de fichier vides. Certaines versions de patch utilisent par dfaut -b, ce qui laisse de nombreux fichiers .orig dans
larborescence et certaines versions (en particulier sous Linux) sont moins bavardes que
dautres (BSD, par exemple). De nombreuses versions (mais pas celle de Solaris) de diff
prennent aussi en charge largument -p, qui tentent dafficher le nom des fonctions C
affectes par le correctif.
Rsistez lenvie de faire diff -u prog.c.orig prog.c. Cela ne peut quentraner une
certaine confusion car patch peut aussi crer des fichiers .orig. vitez aussi de lancer diff
-u prog/prog.c new/prog/prog.c car patch sera trs perturb par le nombre diffrent
de rpertoires dans les chemins.

Voir aussi

man diff ;

man patch ;

man cmp ;

http://directory.fsf.org/GNU/wdiff.html ;

http://furius.ca/xxdiff/ pour un diff disposant dune interface graphique.

wdiff
Un autre outil peu connu existe. Il sappelle wdiff et il est aussi intressant. wdiff
compare des fichiers pour dtecter des modifications dans les mots ; un mot tant
spar des autres par des espaces. Il peut prendre en charge les dcalages de retour
la ligne et essaye dutiliser les chanes termcap pour amliorer la lisibilit du rsultat. Il peut tre utile lorsquune comparaison ligne--ligne nest pas assez prcise et fonctionne de la mme manire que la fonctionnalit word diff dEmacs.
Sachez quil est rarement install par dfaut sur les systmes. Consultez la page
http:// directory.fsf.org/GNU/wdiff.html ou loutil de gestion des paquetages de votre
systme. Voici un exemple daffichage de wdiff :
$ wdiff fichier_original fichier_modifi
Je suis le [-fichier_original,-] {+fichier_modifi,+} et cette ligne
est diffrente.
Cette ligne est identique.
Tout comme celle-ci.
Et celle-l.
Ditto.
Mais celle-[-ci-] {+l+} est diffrente.
Contrairement cette ligne.
Et cette dernire ligne est identique.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

446

Chapitre 17 Maintenance et tches administratives

17.11. Compter les diffrences dans des fichiers


Problme
Vous avez deux fichiers et vous voulez connatre le nombre de diffrences quils comportent.

Solution
Comptez les hunks (cest--dire les blocs de donnes modifies) dans laffichage de
diff :
$ diff -C0 fichier_original fichier_modifi | grep -c "^\*\*\*\*\*"
2
$ diff -C0 fichier_original fichier_modifi
*** fichier_original
Fri Nov 24 12:48:35 2006
--- fichier_modifi
Fri Nov 24 12:48:43 2006
***************
*** 1 ****
! Ligne diffrente du fichier original
--- 1 ---! Ligne diffrente du fichier modifi
***************
*** 6 ****
! Mais cette ligne est diffrente.
--- 6 ---! Mais celle-ci est diffrente.

Si vous voulez seulement savoir si les deux fichiers sont identiques ou non sans vous proccuper du nombre de diffrences, utilisez cmp. Il se terminera la premire diffrence
trouve, ce qui peut conomiser du temps sur les gros fichiers. Tout comme diff, il reste
muet lorsque les fichiers sont identiques, mais il indique lemplacement de la premire
diffrence sil en trouve une :
$ cmp fichier_original fichier_modifi
fichier_original fichier_modifi differ: char 9, line 1

Discussion
Un Hunk (un bloc de description de changements) est le terme technique officiel,
mme si nous avons aussi rencontr des hunks appels chunks . Sachez quil est
possible, en thorie, dobtenir des rsultats lgrement diffrents pour les mmes fichiers compars sur diffrentes machines ou avec diffrentes versions de diff, car le nombre de hunks dpend de lalgorithme utilis par diff. Vous obtiendrez aussi certainement
des rponses diffrentes selon le format du rsultat demand diff, comme dans les
exemples ci-aprs.
Nous avons trouv que linvocation de diff avec un format sans contexte tait la plus partique ici et lutilisation de -C0 la place de -c cre moins de lignes transmettre grep
pour la recherche. Un format unifi a tendance combiner plus de modifications dans
un bloc que ce que nous attentions, ce qui entrane des diffrences :
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.11. Compter les diffrences dans des fichiers

447

$ diff -u fichier_original fichier_modifi | grep -c "^@@"


1
$ diff -u fichier_original fichier_modifi
--- fichier_original
2006-11-24 12:48:35.000000000 -0500
+++ fichier_modifi
2006-11-24 12:48:43.000000000 -0500
@@ -1,8 +1,8 @@
-Ligne diffrente du fichier original
+Ligne diffrente du fichier modifi
Cette ligne est identique.
Tout comme celle-ci.
Et celle-l.
Ditto.
-Mais cette ligne est diffrente.
+Mais celle-ci est diffrente.
Contrairement cette ligne.
Et cette dernire ligne est identique.

Un format normal ou ed de diff fonctionne aussi, mais le motif de recherche grep est plus
compliqu. Mme si notre exemple ne le montre pas, un changement sur plusieurs lignes ressemble 2,3c2,3, ce qui ncessite lutilisation de classes de caractres et plus de
travail que si nous avions utilis -C0 :
$ diff -e fichier_original fichier_modifi | egrep -c
'^[[:digit:],]+[[:alpha:]]+'
2
$ diff fichier_original fichier_modifi | egrep -c
'^[[:digit:],]+[[:alpha:]]+'
2
$ diff fichier_original fichier_modifi
1c1
< Ligne diffrente du fichier original
--> Ligne diffrente du fichier modifi
6c6
< Mais cette ligne est diffrente.
--> Mais celle-ci est diffrente.

Voir aussi

iman diff ;

man cmp ;

man grep ;

http://fr.wikipedia.org/wiki/Diff ;

http://en.wikipedia.org/wiki/Diff.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

448

Chapitre 17 Maintenance et tches administratives

17.12. Effacer ou renommer des fichiers dont le


nom comporte des caractres spciaux
Problme
Vous devez supprimer ou renommer un fichier qui a t cr avec un caractre spcial
et qui entrane un comportement inattendu de rm ou mv. Le cas typique est un fichier
dont le nom commence par un trait dunion, tel que -f ou --help, ce qui entrane linterprtation du nom de fichier comme tant une option par la commande lance.

Solution
Si le fichier commence par un trait dunion, utilisez -- pour indiquer la fin des arguments dune commande, utilisez le chemin absolu (/tmp/-f) ou le chemin relatif (./-f). Si
le fichier comporte dautres caractres spciaux interprts par le shell, comme des espaces ou des astrisques, utilisez les citations. Si vous utilisez la compltion des noms de
fichier (touche de tabulation par dfaut), elle protgera automatiquement les caractres
spciaux pour vous. Vous pouvez aussi encadrer le nom de fichier avec des apostrophes.
$ ls
--help

quel nom *surprenant* !

$ mv --help help
mv: unknown option -- usage: mv [-fiv] source target
mv [-fiv] source ... directory
$ mv -- --help aide
$ mv quel\ nom\ \*surprenant\*\ \! meilleur_nom
$ ls
aide

meilleur_nom

Discussion
Pour comprendre ce qui est rellement excut aprs linterprtation par le shell, prfixez votre commande avec echo :
$ rm *
rm: unknown option -- usage: rm [-f|-i] [-dPRrvW] file ...
$ echo rm *
rm --help quel nom *surprenant* !

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.13. Insrer des en-ttes dans un fichier

449

Voir aussi

http://www.gnu.org/software/coreutils/faq/coreutils-faq.html#How-do-I-remove-files-thatstart-with-a-dash_003f ;

les sections 2.1 et 2.2 de http://www.faqs.org/faqs/unix-faq/faq/part2/ ;

la recette 1.6, Protger la ligne de commande, page 12.

17.13. Insrer des en-ttes dans un fichier


Problme
Vous voulez insrer des donnes en tte dun fichier, par exemple pour lui ajouter un
en-tte aprs lavoir tri.

Solution
Utilisez cat dans un sous-shell.
fichier_temp="temp.$RANDOM$RANDOM$$"
(echo 'ligne statique de dbut1'; cat fichier_donnees) > $fichier_temp \
&& cat $fichier_temp > fichier_donnees
rm $fichier_temp
unset fichier_temp

Vous pouvez aussi utiliser sed, lditeur de f lux. Pour linsertion de texte statique, remarquez que les squences dchappement avec la barre oblique inverse sont interprtes
par GNU sed contrairement dautres versions. De mme, sous certains shells, il peut
tre ncessaire de doubler les barres obliques inverses :
# Tout sed, par exemple, Solaris 10 /usr/bin/sed
$ sed -e '1i\
> ligne statique de dbut1
> ' fichier_donnees
ligne statique de dbut1
1 foo
2 bar
3 baz
$ sed -e '1i\
> ligne statique de dbut1\
> ligne statique de dbut2
> ' fichier_donnees
ligne statique de dbut1
ligne statique de dbut2
1 foo
2 bar
3 baz

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

450

Chapitre 17 Maintenance et tches administratives

# sed GNU
$ sed -e '1iligne statique de dbut1\nligne statique de dbut2'
fichier_donnees
ligne statique de dbut1
ligne statique de dbut2
1 foo
2 bar
3 baz

Pour prfixer un fichier existant :


$ sed -e '$r fichier_donnees' fichier_en-tete
en-tte1
en-tte2
1 foo
2 bar
3 baz

Discussion
La solution dpend des prfrences de chacun. Les utilisateurs aiment cat ou sed, mais
rarement les deux. La version cat est certainement plus simple et plus rapide, la solution
sed est indiscutablement plus souple.
Vous pouvez enregistrer un script sed dans un fichier au lieu de le laisser dans la ligne
de commande. Bien sr, vous pourrez rediriger laffichage dans un nouveau fichier
comme sed -e '$r donnes' en-tete > nouveau_fichier, mais sachez que linode du fichier sera modifi, de mme que dautres attributs comme les permissions ou lappartenance. Pour tout prserver, sauf linode, utilisez loption -i (in-place editing) pour une
dition sur place , si votre version de sed la supporte. Nutilisez pas -i avec le fichier
den-tte insrer, vous diteriez ce fichier. Sachez aussi que Perl dispose dune option
-i similaire qui crit aussi un nouveau fichier, comme sed, mme si Perl fonctionne diffremment de sed dans notre exemple :
# Affiche l'inode
$ ls -i fichier_donnees
509951 fichier_donnees
$ sed -i -e '1iligne statique de dbut1\nligne statique de dbut2'
fichier_donnees
$ cat fichier_donnees
ligne statique de dbut1
ligne statique de dbut2
1 foo
2 bar
3 baz
# Vrifie le changement d'inode
$ ls -i fichier_donnees
509954 fichier_donnees

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.13. Insrer des en-ttes dans un fichier

451

Pour tout prserver (ou si votre sed ne dispose pas de loption -i ou si vous voulez utiliser un fichier den-ttes insrer) :
# Affiche l'inode
$ ls -i fichier_donnees
509951 fichier_donnees
#
#
#
$

$RANDOM n'est disponible que sous bash,


sous d'autres shells, vous pouvez utiliser
la commande mktemp.
fichier_temporaire=$RANDOM$RANDOM

$ sed -e '$r fichier_donnees' fichier_entete > $fichier_temporaire


# N'affiche le fichier que s'il existe et
# s'il n'est pas vide !
$ [ -s "$fichier_temporaire" ] && cat $fichier_temporaire > donnees
$ unset fichier_temporaire
$ cat fichier_donnees
Ligne d'en-tete1
Ligne d'en-tete2
1 foo
2 bar
3 baz
# Vrifie que l'inode N'A PAS chang
$ ls -i fichier_donnees
509951 data

Insrer un fichier den-ttes au dbut dun fichier de donnes est intressant car ce nest
pas intuitif. Si vous essayez de lire6 le fichier fichier_entete la ligne un du fichier
fichier_donnees, vous obtiendrez ceci :
$ sed -e '1r fichier_entete' fichier_donnees
1 foo
Ligne d'en-tete1
Ligne d'en-tete2
2 bar
3 baz

Vous pouvez aussi ajouter les donnes au fichier den-ttes et crire le rsultat dans un
autre fichier. Encore une fois, nutilisez pas sed -i, sinon vous diterez le fichier denttes.
Une autre manire de procder pour insrer avant des donnes est dutiliser cat avec
STDIN comme source et la syntaxe document-ici ou chane-ici . Sachez que la
syntaxe chane-ici nest prise en charge par bash qu partir de la version 2.05b et
quelle ne gre pas linterprtation des squences dchappement avec la barre oblique
inverse, mais elle vite les problmes inhrents aux diffrentes versions de sed.
6. N.d.T. : Au sens sed du mot lire, cest--dire insrer des donnes lues depuis un fichier.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

452

Chapitre 17 Maintenance et tches administratives

# Utilisation de document-ici
$ cat - fichier_donnees <<EoH
> Ligne d'en-tete1
> Ligne d'en-tete2
> EoH
Ligne d'en-tete1
Ligne d'en-tete2
1 foo
2 bar
3 baz

# Utilisation de chane-ici avec une version


# de bash suprieure 2.05b+, sans
# interprtation des squences d'chappement
$ cat - fichier_donnees <<<'Ligne d'en-tete1'
Ligne d'en-tete1
1 foo
2 bar
3 baz

Voir aussi

man cat ;

man sed ;

http://sed.sourceforge.net/sedfaq.html ;

http://sed.sourceforge.net/sed1line.txt ;

http://tldp.org/LDP/abs/html/x15507.html ;

la recette 14.11, Utiliser des fichiers temporaires scuriss, page 304 ;

la recette 17.14, diter un fichier sans le dplacer, page 452.

17.14. diter un fichier sans le dplacer


Problme
Vous voulez diter un fichier sans en modifier linode ou les permissions.

Solution
Cest plus compliqu quil ny parat car de nombreux outils que vous pourriez utiliser
habituellement, tels que sed, vont crire dans un nouveau fichier (et changer dinode),
mme sils font leur possible pour prserver les autres attributs.
La solution vidente est de simplement diter le fichier et dy effectuer vos modifications. Cependant, nous admettons que cette solution montre ses limites dans une utilisation par un script.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.14. diter un fichier sans le dplacer

453

Dans la recette 17.13, page 449, vous avez vu que sed crit dans un nouveau fichier dune
manire ou dune autre. Il existe un anctre de sed qui ne sy prend pas ainsi. Il sappelle
ed et il est aussi polyvalent que son autre descendant, vi. Il se rvle intressant car il
peut tre utilis dans des scripts. Voici donc notre exemple dinsertion en dbut de fichier avec ed :
# Affiche l'inode
$ ls -i fichier_donnees
306189 fichier_donnees
# Utilise printf "%b" pour viter les problmes
# rencontrs avec 'echo -e'.
$ printf "%b" '1\ni\nLigne d'en-tete1\nLigne d'en-tete2\n.\nw\nq\n' | ed -s
fichier_donnees
1 foo
$ cat fichier_donnees
Ligne d'en-tete1
Ligne d'en-tete2
1 foo
2 bar
3 baz
# Vrifie que l'inode n'a PAS chang
$ ls -i fichier_donnees
306189 fichier_donnees

Discussion
Bien sr, vous pouvez enregistrer un script ed dans un fichier, exactement comme vous
pouvez le faire avec sed. Dans ce cas, il peut tre utile de voir quoi ressemble le fichier
pour expliquer la mcanique du script ed :
$ cat script_ed
1
i
Ligne d'en-tete1
Ligne d'en-tete2
.
w
q
$ ed -s fichier_donnees < script_ed
1 foo
$ cat fichier_donnees
Ligne d'en-tete1
Ligne d'en-tete2
1 foo
2 bar
3 baz

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

454

Chapitre 17 Maintenance et tches administratives

Le 1 du script ed indique de se placer sur la premire ligne. i nous place en mode insertion et les deux lignes suivantes sont des donnes brutes. Un unique point (.) sur la ligne quitte le mode insertion, w crit le fichier et q quitte le programme. Loption -s
supprime certaines informations de diagnostic, prvues particulirement pour linterprtation de scripts, mais vous pouvez voir quil reste des informations affiches par ed.
videmment, ed -s fichier_donnees < script_ed > /dev/null prend cela en compte.
Lun des dsavantages de ed est quil ny a plus beaucoup de documentation disponible.
Il existe depuis les dbuts dUnix, mais il nest plus tellement utilis bien que prsent
sur tous les systmes que nous avons tests. Comme la fois vi ( travers ex) et sed (au
moins dans lesprit7) descendent tous les deux de ed, vous devriez pouvoir faire tout ce
dont vous avez besoin. Sachez que ex est un lien symbolique vers vi ou une de ses variantes sur de nombreux systmes, alors que ed est ed !
Une autre manire dobtenir le mme effet est dutiliser sed ou un autre outil, dcrire
le fichier modifi dans un nouveau fichier, puis de le cater dans le fichier dorigine. Manifestement, cest totalement contre productif. Attention, restez prudent car, si la modification choue, il y a de grands risques dcrire un fichier vide dans le fichier originel
(consultez les exemples de la recette 17.13, page 449).

Voir aussi

man ed ;

man ex ;

ls -l `which ex` ;

http://sed.sourceforge.net/sedfaq.html ;

la recette 17.13, Insrer des en-ttes dans un fichier, page 449.

17.15. Utiliser sudo avec un groupe de


commandes
Problme
Vous tes connect en tant quutilisateur et avez besoin dexcuter plusieurs commandes travers sudo ou vous devez utiliser une redirection qui sapplique aux commandes
et non sudo.

Solution
Utilisez sudo pour excuter un sous-shell dans lequel vous pouvez regrouper vos commandes et utiliser la redirection :
sudo bash -c 'commande1 && commande2 || commande3'

7. http://www.columbia.edu/~rh120/ch106.x09.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.15. Utiliser sudo avec un groupe de commandes

455

Cela implique dexcuter un shell en tant que root. Si vous ne le pouvez pas, demandez
votre administrateur systme dcrire un petit script pour cela et de lajouter la description de vos privilges sudo.

Discussion
Si vous essayez une commande comme sudo commande1 && commande2 || commande3 vous
constaterez que commande2 et commande3 sexcutent avec votre compte et non avec celui
de root. La raison est que sudo ninf luence que la premire commande et que la redirection est effectue par votre shell.
Remarquez lutilisation de largument -c avec bash, qui entrane uniquement lexcution des commandes indiques. Sans cela, vous vous trouveriez dans un nouveau shell
interactif en tant que root, ce que vous ne souhaitez probablement pas. Mais, comme
indiqu ci-dessus, avec loption -c vous excuterez tout de mme un shell (non-interactif) en tant que root et vous avez besoin de certains privilges sudo pour le faire. Mac
OS X et certaines distributions Linux, telles que Ubuntu, dsactivent le compte root
pour vous inciter ne vous connecter quavec un compte utilisateur et utiliser sudo
lorsque cest ncessaire (Mac le fait mieux) pour ladministration. Si vous utilisez un tel
systme dexploitation ou que vous avez effectu votre propre configuration de sudo,
vous devriez y arriver. Cependant, si vous employez un environnement verrouill, cette
recette ne fonctionnera peut-tre pas.
Pour savoir si vous devez utiliser sudo et ce que vous avez le droit de faire avec, utilisez
la commande sudo -l. Presque toutes les autres utilisations de sudo que celles listes entraneront probablement un message de scurit adress votre administrateur systme. Vous pouvez essayer dutiliser sudo sudo -V | less en tant quutilisateur ou
uniquement sudo -V | less si vous tes dj connect en tant que root pour obtenir de
nombreuses informations sur la manire dont sudo a t compil et configur sur votre
systme.

Voir aussi

man su ;

man sudo ;

man sudoers ;

man visudo ;

sudo ;

https://help.ubuntu.com/community/RootSudo ;

la recette 14.15, crire des scripts setuid ou setgid, page 312 ;

la recette 14.18, Excuter un script sans avoir les privilges de root, page 317 ;

la recette 14.19, Utiliser sudo de manire plus sre, page 318 ;

la recette 14.20, Utiliser des mots de passe dans un script, page 319.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

456

Chapitre 17 Maintenance et tches administratives

su et sudo
Une bonne pratique consiste utiliser un compte utilisateur normal et ne profiter des privilges de root quen cas de ncessit. Alors que la commande su est pratique, de nombreuses personnes affirment que sudo est mieux. Par exemple :

Cela ncessite plus de travail pour faire fonctionner sudo correctement (en
dautres termes, le verrouiller plus quavec une simple ligne ALL=(ALL)
ALL ) et il est peut-tre un peu moins intuitif utiliser, mais il peut aussi permettre dimposer des habitudes de travail plus sres.

Vous pouvez facilement oublier que vous avez utilis su pour acqurir lidentit de root et effectuer une fausse manipulation malheureuse8.

Devoir taper sudo tout le temps vous aidera vous rappeler ce que vous tes
en train de faire.

sudo permet de dlguer des commandes individuelles dautres utilisateurs


sans devoir leur communiquer le mot de passe de root.

Les deux commandes peuvent intgrer une journalisation et certaines astuces


peuvent les rendre trs proches lune de lautre ; cependant certaines diffrences
significatives subsistent. Les deux plus importantes sont quavec sudo vous saisissez votre propre mot de passe pour confirmer votre identit avant de pouvoir excuter une commande. Ainsi le mot de passe de lutilisateur root nest pas partag
si plusieurs personnes ont besoin de privilges levs. Ce qui nous amne la seconde diffrence ; sudo peut tre trs prcis quant aux commandes quun utilisateur peut ou non excuter. Cette restriction peut tre dlicate, car de nombreuses
applications vous permettent de lancer un shell et de faire autre chose, si vous
pouvez lancer vi avec sudo, vous pouvez dmarrer un interprteur de commandes
et disposer dune invite de commande root sans restriction. Nanmoins, utilis
correctement, sudo demeure un excellent outil.

17.16. Trouver les lignes prsentes dans un


fichier mais pas dans un autre
Problme
Vous avez deux fichiers de donnes et vous devez les comparer pour trouver les lignes
qui nexistent que dans lun des deux.8

Solution
Triez les fichiers et isolez les donnes concernes laide de cut ou de awk, si ncessaire.
Ensuite, utilisez comm, diff, grep ou uniq en fonction de vos besoins.
8. N.d.T. : Il mest dj arriv de vider les tables de routage dun serveur de production dans ces
conditions, alors que je ne voulais que les consulter, en tant connect travers le rseau !

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.16. Trouver les lignes prsentes dans un fichier mais pas dans un autre

457

comm est conu prcisment pour ce genre de problme :


$ cat gauche
enregistrement_01
enregistrement_02.gauche uniquement
enregistrement_03
enregistrement_05.diffrent
enregistrement_06
enregistrement_07
enregistrement_08
enregistrement_09
enregistrement_10
$ cat droit
enregistrement_01
enregistrement_02
enregistrement_04
enregistrement_05
enregistrement_06.diffrent
enregistrement_07
enregistrement_08
enregistrement_09.droit uniquement
enregistrement_10
# Affiche les lignes qui ne sont que dans le
# fichier gauche
$ comm -23 gauche droit
enregistrement_02.gauche uniquement
enregistrement_03
enregistrement_05.diffrent
enregistrement_06
enregistrement_09
# Affiche les lignes qui ne sont que dans le
# fichier droit
$ comm -13 gauche droit
enregistrement_02
enregistrement_04
enregistrement_05
enregistrement_06.diffrent
enregistrement_09.droit uniquement
# N'affiche que les lignes communes
$ comm -12 gauche droit
enregistrement_01
enregistrement_07
enregistrement_08
enregistrement_10

diff vous montrera rapidement toutes les diffrences entre les deux fichiers mais son affichage nest pas particulirement beau et vous navez peut-tre pas besoin de connatre

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

458

Chapitre 17 Maintenance et tches administratives

tous les dtails des diffrences. Les options -y et -w de GNU grep peuvent tre utiles pour
amliorer la lisibilit mais vous avez aussi lhabitude de laffichage standard. Certains
systmes (Solaris par exemple) peuvent utiliser sdiff au lieu de diff -y ou avoir un excutable ddi, tel que bdiff, aux gros fichiers.
$ diff -y -W 60 gauche droit
enregistrement_01
enregistrement_01
enregistrement_02.gauche uniquement
enregistrement_03
enregistrement_05.diffrent
enregistrement_06
enregistrement_07
enregistrement_07
enregistrement_08
enregistrement_08
enregistrement_09
enregistrement_10
enregistrement_10

|
|
|
|

enregistrement_02
enregistrement_04
enregistrement_05
enregistrement_06.diffrent

| enregistrement_09.droit uniquement

$ diff -y -W 60 --suppress-common-lines gauche droit


enregistrement_02.gauche uniquement | enregistrement_02
enregistrement_03
| enregistrement_04
enregistrement_05.diffrent
| enregistrement_05
enregistrement_06
| enregistrement_06.diffrent
enregistrement_09
| enregistrement_09.droit uniquement
$ diff gauche droit
2,5c2,5
< enregistrement_02.gauche uniquement
< enregistrement_03
< enregistrement_05.diffrent
< enregistrement_06
--> enregistrement_02
> enregistrement_04
> enregistrement_05
> enregistrement_06.diffrent
8c8
< enregistrement_09
--> enregistrement_09.droit uniquement

grep peut vous afficher les lignes qui nexistent que dans un fichier et vous pouvez
dterminer lequel si vous en avez besoin. Mais comme cette commande utilise les expressions rgulires, elle ne sera pas capable de traiter les diffrences lintrieur des lignes moins que vous nutilisiez lun des fichiers comme motif de correspondance.
Cette solution devient vite extrmement lente mesure que la taille des fichiers grandit.
Cet exemple affiche toutes les lignes qui existent dans le fichier gauche mais pas dans le
fichier droit :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.16. Trouver les lignes prsentes dans un fichier mais pas dans un autre

459

$ grep -vf droit gauche


enregistrement_03
enregistrement_06
enregistrement_09

Remarquez que seule la ligne enregistrement_03 manque rellement. Les deux


autres lignes sont simplement diffrentes. Si vous avez besoin de dtecter de telles variations, vous devrez utiliser diff. Si vous avez besoin de les ignorer, utilisez cut ou awk pour
isoler les parties dsires dans des fichiers temporaires.
uniq -u peut afficher uniquement les lignes qui ne sont pas rptes dans les fichiers,
mais elle ne vous dira pas de quel fichier elles proviennent (si vous avez besoin de le savoir, utilisez les solutions dj prsentes). uniq -d affiche uniquement les lignes prsentes dans les deux fichiers :
$ sort droit gauche | uniq -u
enregistrement_02
enregistrement_02.gauche uniquement
enregistrement_03
enregistrement_04
enregistrement_05
enregistrement_05.diffrent
enregistrement_06
enregistrement_06.diffrent
enregistrement_09
enregistrement_09.droit uniquement
$ sort droit gauche | uniq -d
enregistrement_01
enregistrement_07
enregistrement_08
enregistrement_10

Discussion
comm est le meilleur choix sil est disponible et que vous navez pas besoin de la puissance de diff.
Vous pouvez avoir besoin de sort et/ou de cut ou awk pour isoler les donnes utiles dans
des fichiers temporaires en liminant les donnes inutiles et travailler partir de ces fichiers si vous ne pouvez pas modifier les fichiers originaux.

Voir aussi

man cmp ;

man diff ;

man grep ;

man uniq.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

460

Chapitre 17 Maintenance et tches administratives

17.17. Conserver les N objets les plus rcents


Problme
Vous devez conserver les N fichiers journaux les plus rcents ou sauvegarder danciens
fichiers dans des rpertoires et les purger, quel que soit leur nombre.

Solution
Crez une liste ordonne des objets, transmettez-les en tant quarguments une fonction, dcalez les arguments de N positions et renvoyez ce quil reste :
# bash Le livre de recettes : func_shift_by
# Affiche les lments d'une liste ou d'une pile en ignorant un nombre donn
# d'lments depuis le dessus de la pile pour que vous puissiez ensuite
# effectuer une des actions restant faire.
#
# Appel : shift_by <nb lments ignorer> <commande ls ou autre>
# Retour : les lments de la pile ou de la liste
#
# Par exemple, liste quelques objets et ne conserve que les 10 premiers.
#
# Il est PRIMORDIAL que vous passiez les lments dans l'ordre pour que
# les objets retirer soient sur le dessus de la pile ou en tte de
# liste. Cette fonction ne fait que retirer le nombre d'entres
# spcifi partir du dbut de la pile.
#
# Vous devriez essayer echo avant d'utiliser rm !
#
# Par exemple :
#
rm -rf $(shift_by $NB_REPERTOIRES_A_CONSERVER $(ls -rd backup.2006*))
#
function shift_by {
# Si $1 est nul ou suprieur $#, les
# arguments restent inchangs. Ce cas ne
# DEVRAIT PAS se produire !
if (( $1 == 0 || $1 > ( $# - 1 ) )); then
echo ''
else
# Retire le nombre d'lments (plus 1) de la liste
shift $(( $1+1 ))
# Retourne ce qu'il reste
echo "$*"
fi
}

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.17. Conserver les N objets les plus rcents

461

Si vous essayez de dcaler les arguments de zro ou de plus que le nombre total darguments ($#), shift ne fera rien. Si vous utilisez shift pour
traiter une liste, puis supprimer ce qui est renvoy, cela revient tout
effacer. Vrifiez que vous testez bien les arguments dcaler pour tre
certain quil y en a plus que le nombre de dcalages effectuer. Notre
fonction effectue ce test.

Par exemple :
$ source shift_by
$ touch {1..9}
$ ls ?
1 2 3 4 5 6 7 8 9
$ shift_by 3 $(ls ?)
4 5 6 7 8 9
$ shift_by 5 $(ls ?)
6 7 8 9
$ shift_by 5 $(ls -r ?)
4 3 2 1
$ shift_by 7 $(ls ?)
8 9
$ shift_by 9 $(ls ?)
# Ne conserve que les 5 derniers objets
$ echo "rm -rf $(shift_by 5 $(ls ?))"
rm -rf 6 7 8 9
# En production, nous devrions commencer par
# tester avant d'effectuer la suppression !
$ rm -rf $(shift_by 5 $(ls ?))
$ ls ?
1 2 3 4 5

Discussion
Vrifiez que vous avez compltement test la fois les arguments renvoys et ce que
vous voulez en faire. Par exemple, si vous voulez supprimer danciennes donnes, utilisez echo pour tester la commande qui sera excute avant de rellement lexcuter. Vrifiez aussi que vous avez une valeur en retour, sinon vous pourriez excuter rm -rf et
obtenir une erreur. Nexcutez jamais une commande telle que rm -rf /$variable, car
si $variable est nulle ou vide, vous allez commencer supprimer le rpertoire racine,
ce qui est particulirement dangereux si vous tes connect en tant que root !

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

462

Chapitre 17 Maintenance et tches administratives

$fichiers__supprimer=$(shift_by 5 $(ls ?))


[ -n $ fichiers__supprimer ] && rm -rf "$fichiers__supprimer"

Cette recette sappuie sur le fait que les arguments dune fonction sont impacts par la
commande shift lintrieur de cette fonction, ce qui facilite le dpilement dobjets (sinon, nous aurions d utiliser des oprations complexes sur les sous-chanes ou une boucle for). Nous devons dcaler de n+1 car le premier argument ($1) est en fait le nombre
dlments dcaler, les lments eux-mme se trouvant dans $2..N. Nous pourrions
aussi crire cette fonction ainsi :
function shift_by {
shift_count=$1
shift
shift $shift_count
echo "$*"
}

Il est possible que le nombre darguments atteigne la valeur systme ARG_MAX (consultez
la recette 15.13, page 357, pour plus de dtails) si les chemins des objets sont trs longs
ou si vous devez manipuler un trs grand nombre dobjets. Dans le premier cas, vous
pouvez diminuer la longueur des arguments en vous plaant dans un rpertoire plus
proche des objets et en rduisant ainsi la longueur des chemins ou en utilisant des liens
symboliques. Dans le second cas, vous pouvez utiliser cette boucle for un peu plus complique :
objets_a_garder=5
compteur=1
for file in /chemin/avec/de/tres/nombreux/fichiers*e*; do
if [ $compteur -gt $objets_a_garder ]; then
restant="$restant $fichier"
fi
(( compteur++ ))
done
[ -n "$restant" ] && echo "rm -rf $restant"

Une mthode habituelle pour effectuer de telles oprations suit un schma comme celui-ci :
rm -rf sauvegarde.3/
mv
sauvegarde.2/ sauvegarde.3/
mv
sauvegarde.1/ sauvegarde.2/
cp -al sauvegarde.0/ sauvegarde.1/

Cela fonctionne trs bien dans de nombreux cas, particulirement lorsque cest combin avec des liens physiques pour conomiser de lespace tout en permettant plusieurs
sauvegardes (consultez le livre Administration Linux 200 %, Hack #42 [ditions
OReilly] de Rob Flickenger). Cependant, si le nombre dobjets existants varie ou nest
pas connu lavance, cette mthode ne peut pas sappliquer.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.18. Filtrer la sortie de ps sans afficher le processus grep

463

Voir aussi

help for ;

help shift ;

Administration Linux 200 %, Hack #42, de Rob Flickenger (ditions OReilly) ;

la recette 13.5, Analyser la sortie avec une fonction, page 265 ;

la recette 15.13, Contourner les erreurs liste darguments trop longue , page 357.

17.18. Filtrer la sortie de ps sans afficher le


processus grep
Problme
Vous voulez filtrer avec grep laffichage de la commande ps en liminant la ligne correspondant au processus grep lui-mme.

Solution
Modifiez le motif de recherche de manire ce quil soit une expression rgulire valide
ne correspondant pas laffichage de ps :
$ ps aux | grep 'ssh'
root 366 0.0 1.2 340
root 25358 0.0 1.9 472
jp 27579 0.0 0.4 152

1588 ?? Is
2404 ?? Ss
540 p0 S+

20Oct06 0:00.68 /usr/sbin/sshd


Wed07PM 0:02.16 sshd: root@ttyp0
3:24PM 0:00.04 grep ssh

$ ps aux | grep '[s]sh'


root 366 0.0 1.2 340
root 25358 0.0 1.9 472

1588 ?? Is
2404 ?? Ss

20Oct06 0:00.68 /usr/sbin/sshd


Wed07PM 0:02.17 sshd: root@ttyp0

Discussion
Cela fonctionne car [s] est une classe de caractres dexpression rgulire ne contenant
que le seul caractre s en minuscule, ce qui signifie que [s]sh correspondra ssh mais
pas la chane grep [s]sh affiche par ps9.
Une autre solution, moins efficace et moins jolie que vous pouvez rencontrer est :
$ ps aux | grep 'ssh' | grep -v grep

Voir aussi

man ps ;

man grep.

9. N.d.T. : Celle que vous avez saisie sur la ligne de commande.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

464

Chapitre 17 Maintenance et tches administratives

17.19. Dterminer si un processus sexcute


Problme
Vous devez savoir si un processus sexcute en ayant ou non dj son identifiant de processus (PID).

Solution
Si vous ne disposez pas dj de son PID, utilisez grep pour filtrer laffichage de la commande ps et savoir si le processus recherch sexcute. Consultez la recette 17.18, page
463, pour connatre la raison du [s]sh.
$ [ "$(ps -ef | grep 'bin/[s]shd')" ] && echo 'ssh trouv' || echo 'ssh
introuvable'

Cette solution est intressante, mais vous savez bien que ce ne sera pas aussi simple.
Principalement cause des diffrentes commandes ps qui existent sur les diffrents systmes.
# bash Le livre de recettes : is_process_running
# Pouvez-vous le croire ?!?
case `uname` in
Linux|AIX) PS_ARGS='-ewwo pid,args'
SunOS)
PS_ARGS='-eo pid,args'
*BSD)
PS_ARGS='axwwo pid,args'
Darwin)
PS_ARGS='Awwo pid,command'
esac

;;
;;
;;
;;

if ps $PS_ARGS | grep -q 'bin/[s]shd'; then


echo 'sshd trouv'
else
echo 'sshd introuvable'
fi

Si vous disposez dun PID, que ce soit partir dun fichier verrou ou dune variable denvironnement, utilisez-le pour diriger votre recherche. Associez-lui une chane de caractres pour tre certain de trouver la ligne voulue dans laffichage. Vous pouvez utiliser
le PID dans grep ou avec loption -p de ps :
# Linux
$ ps -wwo pid,args -p 1394 | grep 'bin/sshd'
1394 /usr/sbin/sshd
# BSD
$ ps ww -p 366 | grep 'bin/sshd'
366 ?? Is
0:00.76 /usr/sbin/sshd

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.20. Ajouter un prfixe ou un suffixe laffichage

465

Discussion
La premire solution ncessite une petite explication. Vous avez besoin de double-apostrophes autour de $( ) pour que si grep affiche quoique ce soit, le test sera valu positivement. Si grep naffiche rien, le test chouera. Vous devez juste vrifier que ps et grep
font exactement ce que vous souhaitez.
Malheureusement, la commande ps est lune de celle qui comporte le plus grand nombre de diffrences selon la version dUnix utilise. Il semblerait que chaque version de
ps dispose darguments diffrents et les interprte de manire diffrente. Tout ce que
nous pouvons vous dire est quil faut tester votre script sur tous les systmes sur lesquels
il sera susceptible de sexcuter, et ceci en dtail.
Vous pouvez facilement chercher tout ce que vous arrivez exprimer travers une expression rgulire, mais vrifiez que les vtres sont suffisamment prcises pour ne correspondre rien dautre. Cest pourquoi nous avons utilis bin/[s]shd au lieu de
[s]shd, qui aurait aussi renvoy les connexions des utilisateurs (consultez la recette
17.18, page 463). En mme temps, /usr/sbin/[s]shd pourrait tre un mauvais choix
dans le cas o certains systmes nutiliseraient pas cet emplacement. La frontire est
mince entre trop et trop peu de prcision. Par exemple, vous pourriez avoir un programme qui puisse sexcuter plusieurs fois simultanment avec des fichiers de configuration diffrents. Vrifiez donc que vous recherchez aussi le fichier de configuration si
vous avez besoin disoler une instance particulire. Le mme principe sapplique aux
utilisateurs, si vous avez suffisamment de privilges pour voir leurs processus.
Mfiez-vous de Solaris car sa version de ps limite la longueur de laffichage des arguments 80 caractres. Si vous avez de longs chemins ou
de longues commandes dans lesquels vous devez rechercher un fichier
de configuration, vous pourriez vous heurter cette limite.

Voir aussi

man ps ;

man grep ;

la recette 17.18, Filtrer la sortie de ps sans afficher le processus grep, page 463.

17.20. Ajouter un prfixe ou un suffixe


laffichage
Problme
Vous aimeriez ajouter un prfixe ou un suffixe chaque ligne affiche par une commande donne. Par exemple, si vous collectez des statistiques last depuis de nombreuses
machines, il sera plus facile de filtrer les donnes avec grep si chaque ligne contient le
nom de la machine.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

466

Chapitre 17 Maintenance et tches administratives

Solution
Redirigez les donnes dans une boucle while read et utilisez printf. Par exemple, nous
allons afficher le nom de lordinateur ($HOSTNAME) suivi dune tabulation et du contenu
de la ligne, pour toutes les lignes non-vides venant de la commande last :
$ last | while read i; do [[ -n "$i" ]] && printf "%b" "$HOSTNAME\t$i\n";
done
# crire un nouveau fichier journal
$ last | while read i; do [[ -n "$i" ]] && printf "%b" "$HOSTNAME\t$i\n";
done > last_ $HOSTNAME.log

Ou vous pouvez utiliser awk pour ajouter du texte chaque ligne :


$ last | awk "BEGIN { OFS=\"\t\" } ! /^\$/ { print \"$HOSTNAME\", \$0}"
$ last | awk "BEGIN { OFS=\"\t\" } ! /^\$/ { print \"$HOSTNAME\", \$0}" \
> last_$HOSTNAME.log

Discussion
Nous utilisons [[ -n "$i" ]] pour retirer toutes les lignes vides de laffichage de last,
puis nous utilisons printf pour afficher les donnes. Lutilisation des citations avec cette
mthode est plus simple mais elle ncessite plus dtapes (last, while et read, au lieu de
last et awk, uniquement). Vous pouvez trouver une mthode plus facile retenir, plus
lisible ou plus rapide que lautre, en fonction de vos besoins.
Nous avons utilis une astuce de la commande awk. Vous verrez souvent des apostrophes autour des commandes awk pour empcher le shell dinterprter les variables de
awk en tant que variables de shell. Cependant, dans notre cas, nous voulons que le shell
value $HOSTNAME, nous avons donc encadr la commande avec des apostrophes doubles, cest--dire chapp les lments de la commande que nous ne voulions pas que le
shell interprte, comme lapostrophe double interne et la variable awk $0, qui contient
la ligne courante.
Pour un suffixe, dplacez simplement la variable $0 :
$ last | while read i; do [[ -n "$i" ]] && printf "%b" "$i\t$HOSTNAME\n";
done
$ last | awk "BEGIN { OFS=\"\t\" } ! /^\$/ { print \"$HOSTNAME\", \$0}"

Vous pourriez aussi utiliser Perl ou sed (dans lexemple, le caractre indique une tabulation obtenue par la combinaison de touches Ctrl-V et Ctrl-I) :
$ last | perl -ne "print qq($HOSTNAME\t\$_) if ! /^\s*$/;"
$ last | sed "s/./$HOSTNAME &/; /^$/d"

Dans la commande Perl, nous avons utilis qq() au lieu dapostrophes doubles pour viter davoir les protger. La dernire partie est lexpression rgulire qui correspond aux
lignes vides ou ne comportant que des espaces. La variable $_ correspond la ligne courante. Dans la commande sed nous avons remplac toutes les lignes contenant au moins
un caractre par le prfixe et le caractre trouv (&), puis nous avons supprim toutes les
lignes vierges.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.21. Numroter les lignes

467

Voir aussi

Effective awk Programming de Arnold Robbins ;

sed & awk de Arnold Robbins et Dale Dougherty ;

la recette 1.6, Protger la ligne de commande, page 12 ;

la recette 13.14, Supprimer les espaces, page 277 ;

la recette 13.17, Traiter des fichiers sans sauts de ligne, page 285.

17.21. Numroter les lignes


Problme
Vous avez besoin de numroter les lignes dun fichier texte pour les utiliser en rfrence
ou comme exemple.

Solution
Merci Michael Wang pour avoir contribu limplmentation suivante en pur shell
et pour nous avoir rappel lexistence de cat -n. Remarquez que notre fichier dexemple
comporte une ligne finale vide :
$ i=0; while IFS= read -r ligne; do (( i++ )); echo "$i $ligne"; done <
lignes
1 ligne 1
2 ligne 2
3
4 ligne 4
5 ligne 5
6

Voici ce que donne cat :


$ cat -n lignes
1 ligne 1
2 ligne 2
3
4 ligne 4
5 ligne 5
6

$ cat -b lignes
1 ligne 1
2 ligne 2
3 ligne 4
4 ligne 5

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

468

Chapitre 17 Maintenance et tches administratives

Discussion
Si vous navez besoin que dafficher le numro de ligne lcran, vous pouvez utiliser
less -N :
$ /usr/bin/less -N nom_fichier
1 ligne 1
2 ligne 2
3
4 ligne 4
5 ligne 5
6
nom_fichier (END)
Les numros de ligne sont bogus dans les anciennes versions de less de
certains systmes RedHat obsoltes. Vrifiez votre version avec less
-V. La version 358+iso254 (par exemple, Red Hat 7.3 & 8.0) est connue
pour tre dfectueuse, les versions 378+iso254 (par exemple, RHEL3) et
382 (RHEL4, Debian Sarge) sont, quant elles, connues pour ne pas
ltre ; nous nen avons pas test dautres. Le problme est subtil et
peut tre en relation avec un vieux correctif iso256. Vous pouvez facilement comparer les numros des dernires lignes avec vi et Perl qui ne
sont pas bogus.

Vous pouvez aussi utiliser vi (ou view, qui est une version de vi sans possibilit de modification) avec la commande :set nu! :
$ vi nom_fichier
1 ligne 1
2 ligne 2
3
4 ligne 4
5 ligne 5
6
~
:set nu!

vi dispose de nombreuses options, vous pouvez lexcuter avec vi +3 -c 'set nu!'


nom_fichier pour activer la numrotation et placer votre curseur directement sur la ligne 3. Si vous voulez plus de contrle sur la manire dont les numros sont affichs,
vous pouvez aussi utiliser nl, awk ou perl :
$ nl lignes
1 ligne 1
2 ligne 2
3 ligne 4
4 ligne 5

$ nl -ba lignes
1 ligne 1

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.22. crire des squences

469

2 ligne 2
3
4 ligne 4
5 ligne 5
6

$
1
2
3
4
5
6

awk '{ print NR, $0 }' nom_fichier


ligne 1
ligne 2

$
1
2
3
4
5
6

perl -ne
ligne
ligne

ligne
ligne

ligne 4
ligne 5

'print qq($.\t$_);' nom_fichier


1
2
4
5

NR et $. sont les numros de ligne dans le fichier dentre respectivement en awk et en


Perl. Il est facile de les utiliser dans laffichage. Remarquez que nous utilisons le caractres pour symboliser une tabulation dans laffichage de Perl alors que awk utilise
une espace par dfaut.

Voir aussi

man cat ;

man nl ;

man awk ;

man less ;

man vi ;

la recette 8.15, Aller plus loin avec less, page 189.

17.22. crire des squences


Problme
Vous avez besoin de gnrer une squence de nombres, ventuellement avec du texte,
pour effectuer par exemple des tests.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

470

Chapitre 17 Maintenance et tches administratives

Solution
Utilisez awk car il devrait fonctionner peu prs partout :
$
1
2
3
4
5

awk 'END { for (i=1; i <= 5; i++) print i, "text"}' /dev/null


text
text
text
text
text

$ awk 'BEGIN { for (i=1; i <= 5; i+=.5) print i}' /dev/null


1
1.5
2
2.5
3
3.5
4
4.5
5

Discussion
Sur certains systmes, Solaris en particulier, awk va se figer en attendant que vous lui
donniez des donnes moins que vous ne lui donniez un fichier tel que /dev/null. Comme cela na aucun impact sur les autres systmes, il est prudent dutiliser cette technique
systmatiquement.
Remarquez que la variable de linstruction print est i, et non $i. Si vous utilisez accidentellement $i, elle sera interprte comme un champ lors du traitement des lignes.
Comme nous ne traitons aucune ligne, $i sera toujours vide.
Les mots-cls BEGIN ou END permettent deffectuer des oprations au dbut ou la fin
du traitement, lorsque lon traite rellement des f lux. Comme ce nest pas le cas, nous
pouvons utiliser indiffremment lun ou lautre pour que awk effectue des actions,
mme sans aucune donne en entre. Dans ce cas, peu importe celui qui est choisi.
Loutil GNU seq effectue exactement ce que cette recette souhaite, mais il nexiste pas sur
tous les systmes par dfaut ; BSD, Solaris et Mac OS X nen disposent pas. Il offre des
options de formatage utiles.
Heureusement, grce bash 2.04 et ultrieur, vous pouvez faire des boucles for sur des
entiers :
#
$
1
2
3
4
5

Bash 2.04+ uniquement


for ((i=1; i<=5; i++)); do echo "$i texte"; done
texte
texte
texte
texte
texte

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.23. muler la commande DOS pause

471

Tout comme avec bash 3.0 et ultrieur, dans lesquels on trouve linterprtation des accolades {x..y}, qui autorise les entiers ou les caractres :
#
$
1
2
3
4
5

Bash 3.0+ uniquement, entiers ou caractres


printf "%s texte\n" {1..5}
texte
texte
texte
texte
texte

$
a
b
c
d
e

printf "%s texte\n" {a..e}


texte
texte
texte
texte
texte

Voir aussi

man seq ;

man awk ;

http://www.faqs.org/faqs/computer-lang/awk/faq/.

17.23. muler la commande DOS pause


Problme
Vous portez des scripts DOS/Windows vers Unix et vous voulez muler la commande
DOS pause.

Solution
Pour ce faire, utilisez la commande read -p dans une fonction :
pause ()
{
read -p 'Appuyez sur une touche...'
}

Discussion
Loption -p suivie par une chane de caractres affiche cette chane avant de lire la saisie
de lutilisateur. Dans ce cas, la chane est la mme que celle affiche par la commande
DOS pause.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

472

Chapitre 17 Maintenance et tches administratives

Voir aussi

help read.

17.24. Formater les nombres


Problme
Vous aimeriez ajouter des sparateurs de milliers dans les grands nombres.

Solution
Selon votre systme et votre configuration, vous devriez pouvoir utiliser le drapeau de
formatage ' de printf avec une locale. Merci Chet Ramey pour cette solution, qui est
de trs loin la plus simple, lorsquelle fonctionne :
$ LC_NUMERIC=fr_FR.UTF-8 printf "%'d\n" 123456789
123 456 789
$ LC_NUMERIC=fr_FR.UTF-8 printf "%'f\n" 123456789,987
123 456 789,987000

Merci Michael Wang pour avoir contribu cette solution en pur shell et pour la discussion associe :
# bash Le livre de recettes : func_commify
function commify {
typeset text=${1}
typeset partie_entiere=${text%%,*}
typeset partie_decimale=${text#${partie_entiere}}
typeset i mise_en_forme
(( i = ${#partie_entiere} - 1 ))
while (( i>=3 )) && [[ ${partie_entiere:i-3:1} == [0-9] ]]; do
mise_en_forme=" ${partie_entiere:i-2:3}${mise_en_forme}"
(( i -= 3 ))
done
echo "${partie_entiere:0:i+1}${mise_en_forme}${partie_decimale}"
}

Discussion
La fonction shell est crite pour suivre la mme logique quune personne utilisant un
crayon et un papier. Tout dabord, vous examinez la chane pour y trouver le sparateur
dcimal, sil existe. Vous ignorez tout ce qui se trouve aprs et ne travaillez que sur la
chane se trouvant avant ce sparateur.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

17.24. Formater les nombres

473

La fonction shell enregistre la chane avant le sparateur dans la variable


$partie_entiere et celle situe aprs le sparateur (en lincluant) dans la variable
$partie_decimale. Sil ny a pas de sparateur, tout se trouve donc dans la variable
$partie_entiere et $partie_decimale est vide. Ensuite, un tre humain se dplacerait
de la droite vers la gauche dans la partie entire et insrerait un sparateur de millier
lorsque ces deux conditions sont satisfaites :

il reste trois caractres ou plus ;

le caractre avant le sparateur est un nombre.

La fonction implmente cette logique dans une boucle while.


La recette 2.16 de la troisime dition de Perl Cookbook de Tom Christiansen et Nathan
Torkington (OReilly Media) propose aussi une solution :
# bash Le livre de recettes : perl_sub_commify
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Ajoute une espace de sparation aux nombres
# Retour : la chane d'entre, avec les nombres # reformats
# Extrait de Perl Cookbook, 3rd edition, 2.16, page 84
sub commify {
@_ == 1 or carp ('Utilisation de la fonction : $withcomma =
commify($un_nombre);');
# Extrait de _Perl_Cookbook_1 page 64, 2.17 ou _Perl_Cookbook_2 page 84,
2.16
my $text = reverse $_[0];
$text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1 /g;
return scalar reverse $text;
}
La France utilise une espace comme sparateur de milliers, mais
dautres pays utilisent une virgule.

Voir aussi

http://sed.sourceforge.net/sedfaq4.html#s4.14 ;

Perl Cookbook, Troisime dition, Recette 2.16, de Tom Christiansen et Nathan Torkington (OReilly Media) ;

la recette 13.18, Convertir un fichier de donnes au format CSV, page 287.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

18
Rduire la saisie

En dpit de laugmentation de la vitesse du processeur, du dbit des communications,


de la vitesse du rseau et des possibilits dentres/sorties, les utilisations de bash doivent
toujours faire face un facteur limitatif : la rapidit de saisie de lutilisateur. Bien entendu, lcriture des scripts constitue notre principal intrt, mais bash nen reste pas moins
souvent employ en mode interactif. Plusieurs techniques dcriture de scripts prsentes peuvent galement tre employes de manire interactive, mais vous devez alors
passer par une phase de saisie longue, moins que vous ne connaissiez des raccourcis.
Les machines tltype des dbuts du systme Unix nacceptaient que 10 caractres par
seconde et un bon oprateur pouvait taper plus rapidement que le clavier ne le permettait. Unix a t dvelopp dans cet environnement et une part de son caractre abrupt
est probablement d au fait que personne ne souhaitait saisir plus de caractres quil
ntait absolument ncessaire pour invoquer des commandes.
Aujourdhui, les processeurs sont tellement rapides quils sont souvent inactifs, dans
lattente de lentre de lutilisateur. Ils peuvent donc examiner lhistorique des commandes et les rpertoires de $PATH pour trouver les commandes possibles et les arguments
valides avant mme que vous nayez termin de les taper.
En combinant les techniques dveloppes pour ces deux situations, nous pouvons rduire normment la saisie ncessaire linvocation des commandes du shell. Par
ailleurs, vous vous apercevrez rapidement que ces mesures dconomies sont galement
bnfiques car elles apportent plus de prcision et aident viter certaines erreurs.

18.1. Naviguer rapidement entre des


rpertoires quelconques
Problme
Vous avez constat que vous vous dplacez frquemment entre deux rpertoires ou plus,
et vous souhaitez ne plus saisir les longs noms de chemins puisque ces rpertoires ne
semblent jamais trs loin lun de lautre.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

476

Chapitre 18 Rduire la saisie

Solution
Utilisez les commandes internes pushd et popd pour manipuler une pile de rpertoires
et pour passer facilement de lun lautre. Voici un exemple simple :
$ cd /tmp/reservoir
$ pwd
/tmp/reservoir
$ pushd /var/log/cups
/var/log/cups /tmp/reservoir
$ pwd
/var/log/cups
$ ls
access_log

error_log

page_log

$ popd
/tmp/reservoir
$ ls
vide plein
$ pushd /var/log/cups
/var/log/cups /tmp/reservoir
$ pushd
/tmp/reservoir /var/log/cups
$ pushd
/var/log/cups /tmp/reservoir
$ pushd
/tmp/reservoir /var/log/cups
$ dirs
/tmp/reservoir /var/log/cups

Discussion
Les piles sont des mcanismes de type dernier entr, premier sorti, et cest ainsi que ces
commandes se comportent. Lorsque vous invoquez pushd sur un nouveau rpertoire,
lancien est conserv dans une pile. Ensuite, la commande popd extrait le rpertoire actuel du sommet de la pile et vous place dans le rpertoire prcdent. Si vous changez de
rpertoires laide de ces commandes, elles affichent, de gauche droite, les valeurs de
la pile, qui correspondent lordre de haut en bas.
En appelant pushd sans prciser de rpertoire, llment au sommet de la pile est chang avec celui juste en dessous. Vous pouvez ainsi basculer entre deux rpertoires en r-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

18.2. Rpter la dernire commande

477

ptant des commandes pushd sans argument. Vous obtenez le mme comportement
avec cd -.
cd peut toujours servir changer de rpertoire de travail, qui se trouve galement au
sommet de la pile des rpertoires. La commande dirs affiche le contenu de la pile, de
gauche droite. Loption -v permet dobtenir une prsentation plus proche dune pile :
$ dirs -v
0 /var/tmp
1 ~/mes/propres/documents
2 /tmp
$

Le tilde (~) reprsente votre rpertoire personnel. Les numros permettent de rorganiser la pile. Si vous invoquez pushd +2, bash place lentre numro 2 au sommet de la pile
(et vous emmne dans ce rpertoire) et dcale les autres :
$ pushd +2
/tmp /var/tmp ~/mes/propres/documents
$ dirs -v
0 /tmp
1 /var/tmp
2 ~/mes/propres/documents
$

Avec un peu de pratique, vous vous dplacerez beaucoup plus rapidement et facilement
entre les rpertoires.

Voir aussi

la recette 1.2, Afficher son emplacement, page 5 ;

la recette 14.3, Dfinir une variable $PATH sre, page 294 ;

la recette 16.5, Dfinir $CDPATH, page 383 ;

la recette 16.13, Concevoir une meilleure commande cd, page 396 ;

la recette 16.20, Commencer une configuration personnalise, page 416.

18.2. Rpter la dernire commande


Problme
Vous venez de saisir une longue et complexe ligne de commande, de celles qui comportent des noms de chemins longs et des arguments complexes. Vous devez lexcuter une
nouvelle fois, mais vous ne souhaitez pas la saisir nouveau dans son intgralit.

Solution
Il existe deux solutions trs diffrentes ce problme. Premirement, saisissez simplement deux points dexclamation linvite et bash affiche et rpte alors la commande
prcdente. Par exemple :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

478

Chapitre 18 Rduire la saisie

$ /usr/bin/ici/un_prog -g -H -yknot -w /tmp/pourplustard


...
$ !!
/usr/bin/ici/un_prog -g -H -yknot -w /tmp/pourplustard
...

La deuxime solution, plus moderne, utilise les touches de direction. En appuyant sur
la touche f lche vers le haut, vous remontez dans la liste des commandes prcdemment mises. Lorsque vous avez trouv celle qui vous intresse, appuyez simplement sur
la touche Entre pour lexcuter nouveau.

Description
La commande est affiche par !! (parfois appele bang bang) afin que vous sachiez ce
qui est excut.

Voir aussi

la recette 16.8, Ajuster le comportement de readline en utilisant .inputrc, page 387 ;

la recette 16.12, Fixer les options de lhistorique du shell, page 393.

18.3. Excuter une commande similaire


Problme
Lexcution dune commande longue et difficile saisir affiche un message derreur indiquant que vous avez fait une petite faute dorthographe au milieu de la ligne. Vous ne
ne souhaitez pas saisir nouveau lintgralit de la commande.

Solution
La commande !! dcrite la recette 18.2, page 477, accepte une chane ddition de type
sed. Ajoutez un caractre deux-points aprs les deux points dexclamation, puis une expression de substitution la syntaxe sed, comme dans lexemple suivant :
$ /usr/bin/ici/un_prog -g -H -yknot -w /tmp/pourplustard
Erreur : -H nest pas reconnue. Pensiez-vous -A ?
$ !!:s/H/A/
/usr/bin/ici/un_prog -g -A -yknot -w /tmp/pourplustard
...

Vous pouvez toujours employer les flches de direction pour parcourir lhistorique des
commandes, mais, pour les commandes longues sur des liaisons lentes, cette syntaxe est
plus efficace, une fois acquise.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

18.4. Effectuer des substitutions sur plusieurs mots

479

Discussion
Lorsque vous utilisez cette fonctionnalit, faites attention aux substitutions. Si vous essayez de modifier loption -g en saisissant !!:s/g/h/, vous modifiez en ralit la premire lettre g, qui se trouve la fin du nom de la commande, et vous tentez donc dexcuter
/usr/bin/ici/un_proh.
La comparaison avec sed est bien adapte ici car la substitution est applique successivement chaque mot de la ligne de commande. Autrement dit, les expressions employes
pour les substitutions ne traversent pas les frontires de mots. Par exemple, vous ne pouvez pas utiliser la commande suivante car -g et -A sont des mots spars pour bash :
s/-g -A/-gA/

Les modifications peuvent cependant affecter la ligne entire. Si vous souhaitez remplacer toutes les occurrences dune expression de la ligne, vous devez ajouter g (pour substitution globale) avant s :
$ /usr/bin/ici/un_prog -g -s -yknots -w /tmp/pourplustard
...
$ !!:gs/s/S/
/uSr/bin/ici/un_prog -g -S -yknotS -w /tmp/pourpluStard
...

Pourquoi ce g doit-il apparatre avant le s et non aprs comme dans la syntaxe sed ? Tout
ce qui apparat aprs la dernire barre oblique fermante est interprt comme du texte
ajouter la commande. Ce fonctionnement est trs pratique lorsque vous souhaitez
ajouter un autre argument la commande lors de sa nouvelle excution.

Voir aussi

la recette 16.8, Ajuster le comportement de readline en utilisant .inputrc, page 387 ;

la recette 16.12, Fixer les options de lhistorique du shell, page 393 ;

la recette 18.2, Rpter la dernire commande, page 477.

18.4. Effectuer des substitutions sur plusieurs


mots
Problme
La syntaxe !!:s/a/b/ limite les substitutions lintrieur dun mot alors que vous voulez quelles traversent les frontires de mots.

Solution
Utilisez le mcanisme de substitution bas sur laccent circonf lexe (^) :
$ /usr/bin/ici/un_prog -g -A -yknot -w /tmp/pourplustard
...

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

480

Chapitre 18 Rduire la saisie

$ ^-g -A^-gB^
/usr/bin/ici/un_prog -gB -yknot -w /tmp/pourplustard

Vous pouvez toujours employer les flches de direction pour parcourir lhistorique des
commandes, mais, pour les commandes longues sur des liaisons lentes, cette syntaxe est
plus efficace, une fois acquise.

Discussion
crivez la substitution sur la ligne de commande en commenant par un accent circonf lexe (^), puis ajoutez le texte remplacer, suivi dun autre accent circonf lexe et du nouveau texte. Un (troisime) accent circonflexe final est ncessaire uniquement si vous
souhaitez ajouter du texte supplmentaire la fin de la ligne :
$ /usr/bin/ici/un_prog -g -A -yknot
...
$ ^-g -A^-gB^ /tmp^
/usr/bin/ici/un_prog -gB -yknot /tmp

Pour supprimer une partie de la commande, remplacez-la par une valeur vide. En voici
deux exemples :
$ /usr/bin/ici/un_prog -g -A -yknot /tmp
...
$ ^-g -A^^
/usr/bin/ici/un_prog -yknot /tmp
...
$ ^knot^
/usr/bin/ici/un_prog -gA -y /tmp
...
$

Le premier utilise les trois accents circonf lexes. Le deuxime exemple omet le troisime
accent. Puisque nous voulons remplacer la partie knot par un texte vide, nous terminons la ligne par un saut de ligne (la touche Entre).
La substitution via laccent circonflexe traverse les frontires de mots et savre trs pratique. De nombreux utilisateurs de bash la considrent plus simple demploi que la syntaxe !!:s/.../.../.

Voir aussi

la recette 16.8, Ajuster le comportement de readline en utilisant .inputrc, page 387 ;

la recette 16.12, Fixer les options de lhistorique du shell, page 393.

18.5. Rutiliser des arguments


Problme
!! permet de rutiliser facilement la dernire commande, mais dans son intgralit,
alors que vous souhaitez rutiliser uniquement le dernier argument.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

18.6. Terminer les noms automatiquement

481

Solution
Utilisez !$ pour indiquer la dernire commande, !:1 pour le premier argument de la
ligne de commande, !:2 pour le deuxime, etc.

Discussion
Il est assez frquent de passer le mme nom de fichier une suite de commandes. Cest
par exemple le cas lorsquun programmeur modifie puis compile un fichier, le remodifie puis le recompile, etc. La commande !$ lui est alors trs pratique :
$ vi /un/long/chemin/saisi/une/seule/fois
...
$ gcc !$
gcc /un/long/chemin/saisi/une/seule/fois
...
$ vi !$
vi /un/long/chemin/saisi/une/seule/fois
...
$ gcc !$
gcc /un/long/chemin/saisi/une/seule/fois

Non seulement vous conomisez de la saisie, mais vous vitez galement des erreurs de
frappe. Si vous vous trompez dans lcriture du nom du fichier lors de la compilation,
alors vous ne compilez pas le fichier que vous venez de modifier. Avec !$, vous obtenez
toujours le nom du fichier sur lequel vous venez de travailler. Si largument qui vous
intresse se trouve au milieu de la ligne de commande, vous pouvez y faire rfrence
grce aux commandes !: numrotes. En voici un exemple :
$ munge /opt/le/long/chemin/vers/un/fichier | more
...
$ vi !:1
vi /opt/le/long/chemin/vers/un/fichier

Si, dans ce cas, vous utilisez !$, vous obtenez more, ce qui nest pas vraiment le nom du
fichier que vous souhaitez modifier.

Voir aussi

la page de manuel de bash concernant les Indicateurs de mots .

18.6. Terminer les noms automatiquement


Problme
Certains noms de chemin sont plutt longs. Puisque bash sexcute sur un ordinateur,
vous aimeriez quil vous aide.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

482

Chapitre 18 Rduire la saisie

Solution
En cas de doute, appuyez sur la touche Tab. bash tente alors de complter le nom de chemin votre place. Si vous nobtenez rien, il peut y avoir deux raisons : soit le dbut du
chemin ne correspond aucun rpertoire, soit il correspond plusieurs rpertoires. Appuyez une deuxime fois sur la touche Tab pour obtenir la liste des choix possibles. bash
raffiche ensuite la ligne que vous aviez saisie. Tapez quelques caractres supplmentaires, afin de lever lambigut, puis appuyez de nouveau sur la touche Tab pour que bash
complte largument votre place.

Discussion
bash est suffisamment intelligent pour limiter la slection certains types de fichiers. Si
vous saisissez unzip et le dbut dun nom de chemin, lappui sur la touche Tab affiche uniquement les fichiers qui se terminent par .zip, mme si dautres ont des noms
qui correspondent ce que vous avez indiqu. Par exemple :
$ ls
monfichier.c
monfichier.o
monfichier.zip
$ ls -lh monfichier<tab><tab>
monfichier.c
monfichier.o
monfichier.zip
$ ls -lh monfichier.z<tab>ip
-rw-r--r-1 moi mongroupe 1.9M 2006-06-06 23:26 monfichier.zip
$ unzip -l monfichier<tab>.zip
...

Voir aussi

la recette 16.8, Ajuster le comportement de readline en utilisant .inputrc, page 387 ;

la recette 16.17, Amliorer la compltion programmable, page 406.

18.7. Assurer la saisie


Problme
Il est tellement facile de saisir involontairement le mauvais caractre. Mme pour une
commande bash simple, cette erreur peut avoir des consquences fcheuses vous
pouvez dplacer ou supprimer les mauvais fichiers. Lorsque la correspondance de motifs intervient galement, le problme est encore plus intressant, car une faute de saisie
dans le motif peut conduire des rsultats totalement diffrents de lobjectif initial.

Solution
Utilisez lhistorique et les raccourcis clavier pour reprendre les arguments sans les ressaisir, rduisant ainsi les possibilits de fautes de frappe. Si vous avez besoin dun motif
complexe pour trouver des fichiers, testez-le avec echo, puis, lorsquil est au point, utilisez !$ pour le reprendre. Par exemple :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

18.7. Assurer la saisie


$ ls
ab1.txt ac1.txt jb1.txt
$ echo *1.txt
ab1.txt ac1.txt jb1.txt
$ echo [aj]?1.txt
ab1.txt ac1.txt jb1.txt
$ echo ?b1.txt
ab1.txt jb1.txt
$ rm !$
rm ?b1.txt
$

483

wc3.txt

Discussion
echo permet de voir les rsultats dune correspondance de motifs. Ds que vous obtenez
ce que vous souhaitez, vous pouvez lutiliser avec la commande relle. Dans notre exemple, nous supprimons des fichiers et il est prfrable de ne pas se tromper.
Dautre part, avec les commandes dhistorique, vous pouvez ajouter le modificateur :p
pour que bash affiche la commande, mais sans lexcuter. Vous disposez ainsi dune
autre manire de contrler les substitutions. Voici son utilisation dans lexemple prcdent :
$ echo ?b1.txt
ab1.txt jb1.txt
$ rm !$:p
rm ?b1.txt
$

:p a demand bash dafficher la commande, sans lexcuter. Notez que largument est
?b1.txt et quil nest pas remplac par les deux noms de fichiers. Vous pouvez ainsi voir
ce qui sera excut et ce nest quau moment de cette excution que le shell remplacera
le motif par les deux noms de fichiers. Pour obtenir cette expansion, utilisez la commande echo.

Voir aussi

la page de manuel de bash la section Modificateurs pour les modificateurs


accepts aprs les deux-points (:) et utilisables avec les commandes dhistorique ;

la section tapes du traitement de la ligne de commande, page 569.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19
Bourdes du dbutant

Personne nest parfait. Nous ne sommes pas labri des erreurs, en particulier lors de
nos premiers pas dans un domaine. Nous avons tous fait lerreur stupide qui semble tellement vidente une fois quelle a t explique. Nombre dentre nous ont cru au dysfonctionnement du systme car les commandes invoques taient parfaitement
correcte, jusquau moment o le caractre manquant, qui fait toute la diffrence, a t
repr. Certaines erreurs semblent classiques, quasiment prvisibles, chez les dbutants.
Ainsi, nous avons tous appris que les scripts ne sexcutaient pas tant quils navaient pas
les autorisations dexcution (un cas tellement frquent chez les novices). prsent,
avec notre exprience, nous ne faisons plus ces erreurs. Quoique ! Personne nest parfait.

19.1. Oublier les autorisations dexcution


Problme
Lcriture de votre script est termine et vous voulez lessayer. Lorsque vous lexcutez,
vous obtenez le message derreur suivant :
$ ./monScript
bash: ./monScript: Permission non accorde
$

Solution
Vous avez deux possibilits. Premirement, vous pouvez invoquer bash en lui passant le
nom du script en paramtre :
$ bash monScript

Deuximement (solution recommande), vous pouvez donner au script des autorisations dexcution afin de pouvoir le lancer directement :
$ chmod a+x monScript
$ ./monScript
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

486

Chapitre 19 Bourdes du dbutant

Discussion
Les deux mthodes permettent dexcuter le script. Sil doit tre utilis souvent, il est
prfrable de lui donner des autorisations dexcution. Il suffit de le faire une seule fois
pour que vous puissiez linvoquer directement. Avec ces autorisations, il ressemble
une commande, puisquil nest plus ncessaire dinvoquer explicitement bash (bien videmment, bash est toujours invoqu, mais implicitement).
Nous avons utilis a+x pour donner des autorisations dexcution tout le monde. Il ny
a pas vraiment de raison de limiter les autorisations dexcution dun fichier, sauf sil se
trouve dans un rpertoire o dautres personnes peuvent rencontrer accidentellement
votre excutable (par exemple, si, en tant quadministrateur systme, vous placez votre
cration dans /usr/bin). Si le fichier dispose des autorisations de lecture pour tout le
monde, les autres utilisateurs peuvent excuter le script laide de la premire forme
dinvocation, en faisant explicitement rfrence bash. Les autorisations des scripts shell
sont souvent 0700, pour les personnes suspicieuses ou prudentes (autorisations en lecture, criture et excution uniquement au propritaire), et 0755 pour les personnes les
plus ouvertes ou sans souci (autorisations en lecture et excution pour tout le monde).

Voir aussi

man chmod ;

la recette 14.13, Fixer les autorisations, page 310 ;

la recette 15.1, Trouver bash de manire portable, page 334 ;

la recette 19.3, Oublier que le rpertoire de travail nest pas dans $PATH, page 488.

19.2. Rsoudre les erreurs Aucun fichier ou


rpertoire de ce type
Problme
Vous avez accord des autorisations dexcution, comme le dcrit la recette 19.1, page
485, mais le lancement du script gnre une erreur Aucun fichier ou rpertoire de ce
type .

Solution
Essayez de dmarrer le script en utilisant explicitement bash :
$ bash ./errone

Si cela fonctionne, le problme provient des autorisations ou dune faute de frappe dans
la ligne shebang. Si vous obtenez dautres erreurs, les fins de ligne ne sont probablement
pas valides. Cela se produit lorsque vous modifiez le fichier sous Windows (peut-tre via
Samba) ou si vous avez simplement recopi le fichier depuis un autre emplacement.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19.2. Rsoudre les erreurs Aucun fichier ou rpertoire de ce type

487

Pour rsoudre ce problme, essayez le programme dos2unix ou consultez la recette 8.11,


page 185. Si vous utilisez dos2unix, il va probablement crer un nouveau fichier et supprimer lancien. Cette opration modifie les autorisations, change probablement le propritaire ou le groupe et affecte les liens physiques. Si vous ntes pas certain des
implications, retenez que vous devrez probablement utiliser nouveau chmod (voir la
recette 19.1, page 485).

Discussion
Si les fins de ligne ne sont pas correctes (cest--dire diffrentes du code ASCII 10 ou 0a
en hexadcimal), lerreur obtenue dpend de la ligne shebang. Voici quelques exemples
pour un script nomm errone :
$ cat errone
#!/bin/bash echo "Bonjour tout le monde !"
# Correct.
$ ./errone
Bonjour tout le monde !

# Si le fichier contient des fins de ligne DOS, nous obtenons :


$ ./errone
: invalid option
Usage: /bin/bash [GNU long option] [option] ...
[...]

# Ligne shebang diffrente :


$ cat ./errone
#!/usr/bin/env bash
echo "Bonjour tout le monde !"
$ ./errone
: Aucun fichier ou rpertoire de ce type

Voir aussi

la recette 8.11, Convertir les fichiers DOS au format Linux/Unix, page 185 ;

la recette 14.2, viter lusurpation de linterprteur, page 294 ;

la recette 15.1, Trouver bash de manire portable, page 334 ;

la recette 19.1, Oublier les autorisations dexcution, page 485.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

488

Chapitre 19 Bourdes du dbutant

19.3. Oublier que le rpertoire de travail nest


pas dans $PATH
Problme
Lcriture de votre script est termine et vous voulez lessayer. Vous navez pas oubli de
lui donner des autorisations dexcution. Mais, lorsque vous lexcutez, vous obtenez le
message derreur suivant :
$ monScript
bash: monScript: command not found
$

Solution
Ajoutez le rpertoire de travail la variable $PATH, ce que nous dconseillons, ou invoquez le script en incluant le rpertoire courant (./) :
$ ./monScript

Discussion
Les dbutants oublient souvent dajouter ./ avant le script quils souhaitent lancer.
Nous avons dj beaucoup discut de la variable $PATH et nous ne reviendrons pas sur
cet aspect, except pour vous rappeler une solution adapte aux scripts frquemment
utiliss.
Une pratique courante consiste placer vos scripts dans un sous-rpertoire bin de votre
rpertoire personnel et ajouter celui-ci votre variable $PATH. Vous pouvez ainsi excuter vos scripts sans les prfixer par ./.
Lajout de votre rpertoire bin la variable $PATH ne prsente quune difficult : dans
quel script de dmarrage doit-il se faire ? Il ne faut pas choisir .bashrc car il est invoqu
lors de la cration dun sous-shell et le rpertoire sera donc ajout votre chemin chaque fois que vous excuterez dautres commandes ou basculerez vers un shell depuis un
diteur. Il est inutile de multiplier les occurrences du rpertoire bin dans la variable
$PATH.
La modification doit se faire dans le profil douverture de session adquat pour bash.
Daprs sa page de manuel, lors de la connexion, bash recherche ~/.bash_profile,
~/.bash_login et ~/.profile, dans cet ordre, et il excute les commandes du premier fichier
lisible trouv . Vous pouvez donc modifier le fichier dj existant dans votre rpertoire
personnel ou, si aucun deux nexiste, crer ~/.bash_profile, puis placez la ligne suivante
la fin du fichier (ou ailleurs si vous comprenez parfaitement le fonctionnement du fichier de profil) :
PATH="${PATH}:$HOME/bin"

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19.4. Nommer un script test

489

Voir aussi

la recette 4.1, Lancer nimporte quel excutable, page 71 ;

la recette 14.3, Dfinir une variable $PATH sre, page 294 ;

la recette 14.9, Trouver les rpertoires modifiables mentionns dans $PATH, page 300 ;

la recette 14.10, Ajouter le rpertoire de travail dans $PATH, page 303 ;

la recette 15.2, Dfinir une variable $PATH de type POSIX, page 335 ;

la recette 16.3, Modifier dfinitivement $PATH, page 376 ;

la recette 16.4, Modifier temporairement $PATH, page 377 ;

la recette 16.9, Crer son rpertoire priv dutilitaires, page 389 ;

la recette 16.18, Utiliser correctement les fichiers dinitialisation, page 411.

19.4. Nommer un script test


Problme
Vous avez crit un script bash pour tester quelques aspects intressants lus dans cet
ouvrage. Vous avez tout saisi correctement, avez donn les autorisations dexcution au
fichier et avez plac le script dans lun des rpertoires de $PATH. Mais, lorsque vous lexcutez, rien ne se produit.

Solution
Ne nommez pas votre script test. Ce nom est celui dune commande interne du shell.

Discussion
Il est assez naturel de nommer un fichier test lorsque lobjectif est dessayer rapidement
un petit morceau de code. Malheureusement, test est une commande interne du shell
et donc un mot rserv. Vous pouvez le vrifier avec la commande type :
$ type test
test is a shell builtin
$

Puisquil sagit dune commande interne, lajustement du chemin ne rsout rien. Vous
devez crer un alias, mais nous vous le dconseillons fortement dans ce cas. Donnez simplement un autre nom votre script ou invoquez-le en prcisant un nom de chemin :
./test ou /home/chemin/test.

Voir aussi

la section Commandes internes et mots rservs, page 508.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

490

Chapitre 19 Bourdes du dbutant

19.5. Sattendre pouvoir modifier les


variables exportes
Problme
Les dbutants pensent souvent, tort, pouvoir traiter les variables exportes comme les
variables globales dans un environnement de programmation. Cependant, les variables
exportes sont sens unique : elles sont incluses dans lenvironnement du script shell
invoqu, mais, si vous changez leurs valeurs, ces modifications ne sont pas vues par le
script appelant.
Voici un premier script qui fixe la valeur dune variable, invoque un second script, puis
affiche la valeur de la variable une fois le second script termin. Son excution montre
quelle na pas chang :
$ cat premier.sh
#
# Exemple simple dune erreur classique.
#
# Fixer la valeur :
export VAL=5
printf "VAL=%d\n" $VAL
# Invoquer le second script :
./second.sh
#
# Voir ce qui a chang (en fait, rien !)
printf "%b" "retour dans premier\n"
printf "VAL=%d\n" $VAL
$

Le second script manipule une variable nomme $VAL :


$ cat second.sh
printf "%b" "dans second\n"
printf "initialement VAL=%d\n" $VAL
VAL=12
printf "aprs modification VAL=%d\n" $VAL
$

Voici ce que produit lexcution du premier script (qui invoque le second) :


$ ./premier.sh
VAL=5
dans second
initialement VAL=5
aprs modification VAL=10
retour dans premier
VAL=5
$

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19.6. Oublier des guillemets lors des affectations

491

Solution
Rappelez-vous cette blague bien connue :
Le patient : Docteur, jai mal quand je fais comme a.
Le mdecin : Et bien ne le faites pas.

Notre solution reprend le conseil du mdecin : ne faites pas cela. Vous devez structurer
vos scripts shell de manire viter cette forme dchange. Une manire de procder
consiste afficher explicitement les rsultats du second script et programmer le premier pour quil linvoque avec loprateur $( ) (ou `` pour les anciens shells). Dans le
premier script, la ligne ./second.sh devient VAL=$(./second.sh). Le second script doit
envoyer la valeur finale (et uniquement cette valeur) sur STDOUT (ses autres messages
peuvent tre dirigs vers STDERR) :
$ cat second.sh
printf "%b" "dans second\n"
>&2
printf "initialement VAL=%d\n" $VAL
>&2
VAL=12
printf "aprs modification VAL=%d\n" $VAL >&2
echo $VAL
$

Discussion
Les variables denvironnement exportes ne sont pas des variables globales partages
entre les scripts. Il sagit dune communication sens unique. Les variables exportes
sont runies et passes pendant linvocation dun (sous-)processus Linux ou Unix ; voir
la page de manuel de fork(2). Aucun mcanisme ne permet de renvoyer ces variables
denvironnement au processus parent. Noubliez pas quun processus parent peut crer
de trs nombreuses processus enfants. Sil tait possible de retourner des valeurs depuis
un processus enfant, les valeurs de quel enfant le parent obtiendrait-il ?

Voir aussi

la recette 5.5, Exporter des variables, page 92 ;

la recette 10.4, Dfinir des fonctions, page 211 ;

la recette 10.5, Utiliser des fonctions : paramtres et valeur de retour, page 213.

19.6. Oublier des guillemets lors des


affectations
Problme
Votre script affecte des valeurs une variable, mais, lors de son excution, le shell gnre
un message de type commande non trouve pour la valeur de laffectation.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

492

Chapitre 19 Bourdes du dbutant

$ cat bourde1.sh
#!/bin/bash # Erreur classique :
# X=$Y $Z
# Ce nest pas quivalent :
# X="$Y $Z"
#
OPT1=-l
OPT2=-h
TOUTESOPT=$OPT1 $OPT2
ls $TOUTESOPT .
$
$ ./bourde1.sh
bourde1.sh: line 10: -h: command not found
aaa.awk cdscript.prev ifexpr.sh oldsrc xspin2.sh
$

Solution
Vous devez placer des guillemets autour de la partie droite de laffectation $TOUTESOPT.
La ligne :
TOUTESOPT=$OPT1 $OPT2

doit scrire ainsi :


TOUTESOPT="$OPT1 $OPT2"

Discussion
Le problme nest pas de perdre les espaces incluses entre les arguments. Le problme
vient prcisment de ces espaces. Si les arguments taient combins, par exemple,
laide dune barre oblique ou sil ny avait pas despace, ce problme napparatrait pas.
En effet, les arguments constitueraient un seul mot et donc une seule affectation.
Mais, lespace intermdiaire demande bash de traiter cette ligne comme deux mots spars. Le premier constitue une affectation de variable. Cette forme daffectation avant
une commande indique bash de fixer la variable une valeur donne uniquement
pour la dure de la commande la commande tant le mot qui vient ensuite sur la ligne. Sur la ligne suivante, la variable reprend son ancienne valeur ou nest pas dfinie.
Le deuxime mot de notre exemple est donc pris pour une commande. Cest lui qui est
lorigine du message command not found . Bien sr, il est possible que la valeur de
$OPT2 corresponde au nom dun excutable (peu probable dans notre cas avec ls), mais
cette situation peut conduire des rsultats fcheux.
Avez-vous remarqu que, dans notre exemple, la commande ls excute nutilise pas le
format daffichage long mme si nous avons ajout (tout au moins essay dajouter)
loption -l ? Cela montre que $TOUTESOPT nest plus dfinie. Elle a t fixe pour la dure de la commande prcdente, cest--dire la commande -h (inexistante).
Lorsque la ligne est rserve laffectation, la variable est dfinie pour toute la suite du
script. Lorsque laffectation se fait au dbut dune ligne, avant une commande, la variable est dfinie uniquement pour la dure de lexcution de cette commande.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19.7. Oublier que la correspondance de motifs trie par ordre alphabtique

493

En gnral, il est prfrable de placer entre guillemets la valeur affecte une variable
du shell. Ainsi, vous tes certain deffectuer une seule affectation et de ne pas rencontrer
ce problme.

Voir aussi

la recette 5.9, Accepter les paramtres contenant des espaces, page 97.

19.7. Oublier que la correspondance de motifs


trie par ordre alphabtique
Attention, bash trie par ordre alphabtique les rsultats dune correspondance de
motifs :
$ echo x.[ba]
x.a x.b
$

Bien que vous ayez prcis b puis a entre les crochets, les rsultats obtenus par la correspondance de motifs sont tris par ordre alphabtique avant dtre passs la commande
excuter. Autrement dit, vous ne devez pas excuter la commande suivante :
$ mv x.[ba]
$

en pensant quelle sera convertie en celle-ci :


$ mv x.b x.a

En ralit, la commande est :


$ mv x.a x.b

car le tri alphabtique du rsultat est effectu avant son insertion sur la ligne de commande, ce qui produit exactement le contraire de ce que vous souhaitiez !

19.8. Oublier que les tubes crent des


sous-shells
Problme
Vous disposez dun script qui lit lentre dans une boucle while et qui fonctionne
parfaitement :
COMPTEUR=0
while read PREFIXE CORPS
do
# ...
if [[ $PREFIXE == "abc" ]]
then
let COMPTEUR++
fi

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

494

Chapitre 19 Bourdes du dbutant

# ...
done
echo $COMPTEUR

Puis, vous le modifiez afin quil lise depuis un fichier :


cat $1 | while read PREFIXE CORPS
do
# ...

Mais, il ne fonctionne plus... $COMPTEUR vaut toujours zro.

Solution
Les tubes crent des sous-shells. Les modifications ralises lintrieur de la boucle
while naffectent pas les variables qui se trouvent lextrieur. En effet, la boucle est effectue dans un sous-shell.
La solution consiste procder diffremment. Dans cet exemple, au lieu dutiliser cat
pour envoyer le contenu du fichier dans linstruction while via un tube, vous devez employer la redirection des entres/sorties pour que le contenu provienne dune entre redirige et non dun tube :
COMPTEUR=0
while read PREFIXE CORPS
do
# ...
done < $1
echo $COMPTEUR

Si cette approche ne convient pas votre problme, vous devez imaginer une autre solution.

Discussion
Si vous ajoutez une instruction echo lintrieur de la boucle while, vous pouvez constater que la valeur de $COMPTEUR augmente, mais, une fois la boucle termine, elle revient zro. La mise en uvre des tubes de commandes dans bash fait que chacune des
commandes est excute dans son propre sous-shell. Par consquent, la boucle while se
trouve dans un sous-shell et non le shell principal. Si vous avez export $COMPTEUR, la
boucle dmarre avec sa valeur dans le shell principal, mais, puisquelle se trouve dans
un sous-shell, il est impossible de remonter sa valeur au shell parent.
Selon la quantit dinformations renvoyer au shell parent et selon les oprations effectuer lextrieur de la boucle aprs le tube, il existe diffrentes techniques possibles.
Lune delles consiste prendre les oprations supplmentaires et les placer dans un
sous-shell qui inclut la boucle while :
COMPTEUR=0
cat $1 | ( while read PREFIXE CORPS
do
# ...

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19.8. Oublier que les tubes crent des sous-shells

495

done
echo $COMPTEUR )

Lemplacement des parenthses est crucial. Nous avons explicitement dlimit une section du script pour quelle sexcute dans un sous-shell. Elle inclut la boucle while et les
oprations effectuer une fois cette boucle termine (dans cet exemple, nous affichons
simplement la valeur de $COMPTEUR). Puisque les instructions while et echo ne se trouvent pas dans un tube, elles sexcutent toutes deux dans le mme sous-shell cr par les
parenthses. La valeur de $COMPTEUR obtenue pendant la boucle while est conserve jusqu la fin du sous-shell, cest--dire jusqu la parenthse droite finale.
Avec cette technique, il est prfrable que la prsentation du code mette en vidence
lutilisation du sous-shell. Voici le script complet remis en forme :
COMPTEUR=0
cat $1 |
(
while read PREFIXE CORPS
do
# ...
if [[ $PREFIXE == "abc" ]]
then
let COMPTEUR++
fi
# ...
done
echo $COMPTEUR
)

Lorsque les oprations effectuer aprs la boucle while sont plus lourdes, cette technique doit tre tendue. Les instructions peuvent tre places dans des fonctions incluses
dans le sous-shell. Le rsultat de la boucle while peut galement tre affich avec echo
(comme cest le cas dans notre exemple) et envoy par un tube la phase suivante du
processus (qui sexcute dans son propre sous-shell) :
COMPTEUR=0
cat $1 |
(
while read PREFIXE CORPS
do
# ...
if [[ $PREFIXE == "abc" ]]
then
let COMPTEUR++
fi
# ...
done
echo $COMPTEUR
) | read COMPTEUR
# suite du code...

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

496

Chapitre 19 Bourdes du dbutant

Voir aussi

lentre #E4 de la FAQ de bash http://tiswww.tis.case.edu/~chet/bash/FAQ ;

la recette 10.5, Utiliser des fonctions : paramtres et valeur de retour, page 213 ;

la recette 19.5, Sattendre pouvoir modifier les variables exportes, page 490.

19.9. Rinitialiser le terminal


Problme
Vous avez interrompu une session SSH et vous voyez prsent ce que vous saisissez. Ou
bien, vous avez affich par mgarde un fichier binaire et la fentre de terminal contient
du charabia.

Solution
Saisissez stty sane et appuyez sur la touche Entre, mme si vous ne voyez pas ce que
vous tapez, pour rinitialiser le terminal. Vous pouvez commencer par appuyer plusieurs fois sur la touche Entre afin dtre certain que la ligne de commande est vide
avant de saisir la commande stty.
Si ce problme est frquent, crez un alias qui sera plus facile saisir en aveugle.

Discussion
Lorsquon interrompt certaines anciennes versions de ssh linvite du mot de passe,
lcho du terminal (laffichage des caractres au fur et mesure de leur saisie, non la
commande echo du shell) peut tre dsactiv. Dans ce cas, vous ne voyez plus ce que vous
saisissez. Selon le type dmulation employe, laffichage dun fichier binaire peut galement modifier le fonctionnement du terminal. Dans ces deux cas, le paramtre sane
de stty tente de remettre le terminal dans sa configuration par dfaut. Cela inclut la restauration de lcho, afin que les caractres taps au clavier saffichent, et lannulation des
modifications tranges apportes aux paramtres du terminal.
Lapplication mettant en uvre le terminal propose peut-tre une fonction de rinitialisation. Consultez les options des menus et la documentation. Vous pouvez galement
essayer les commandes reset et tset. Cependant, nos tests de stty sane ont donn les rsultats attendus, alors que reset et tset ont eu des interventions plus drastiques.

Voir aussi

man reset ;

man stty ;

man tset.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19.10. Supprimer des fichiers avec une variable vide

497

19.10. Supprimer des fichiers avec une variable


vide
Problme
Une variable du script contient la liste des fichiers supprimer, peut-tre pour la phase
de nettoyage la fin du script. Mais, cette variable est vide et des oprations fcheuses
se produisent.

Solution
Nexcutez jamais une commande comme la suivante :
rm -rf $fichiers_a_supprimer

Et encore moins celle-ci :


rm -rf /$fichiers_a_supprimer

En revanche, vous pouvez invoquer :


[ "$fichiers_a_supprimer" ] && rm -rf $fichiers_a_supprimer

Discussion
Le premier exemple nest pas trop dangereux, il gnre simplement une erreur. Le
deuxime est particulirement risqu car il tente deffacer votre rpertoire racine. Si
vous tes un utilisateur normal (comme ce devrait tre le cas, voir la recette 14.18, page
317), les consquences sont limites. En revanche, si vous tes lutilisateur root, vous venez simplement de dtruire votre systme (cela nous est arriv).
La solution est simple. Vous devez commencer par vrifier que la variable contient une
valeur et vous ne devez jamais la faire prcder par /.

Voir aussi

la recette 14.18, Excuter un script sans avoir les privilges de root, page 317 ;

la recette 18.7, Assurer la saisie, page 482.

19.11. Constater un comportement trange de


printf
Problme
Votre script gnre des valeurs qui ne correspondent pas ce que vous attendez. Examinons le script simple suivant et sa sortie :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

498

Chapitre 19 Bourdes du dbutant

$ bash scriptBizarre
noeuds corrects : 0
noeuds invalides : 6
noeuds manquants : 0
CORRECTS=6 INVALIDES=0 MANQUANTS=0
$
$ cat scriptBizarre
#!/bin/bash invalides=6
printf "noeuds corrects : %d\n" $corrects
printf "noeuds invalides : %d\n" $invalides
printf "noeuds manquants : %d\n" $manquants
printf "CORRECTS=%d INVALIDES=%d MANQUANTS=%d\n" $corrects $invalides
$manquants

Pourquoi la valeur des nuds corrects affiche est-elle 6 alors quil sagit de celle des
nuds invalides ?

Solution
Initialisez les variables (par exemple 0) ou placez des guillemets autour de leur rfrence dans les lignes printf.

Discussion
Que se passe-t-il ? bash effectue ses substitutions sur la dernire ligne. Lorsquil value
$corrects et $manquants, elles sont toutes deux nulles, vides ou absentes. La ligne printf
excute est donc la suivante :
printf "CORRECTS=%d INVALIDES=%d MANQUANTS=%d\n" 6

Lorsque linstruction printf tente dafficher les trois valeurs dcimales (les trois formats
%d), elle trouve une valeur (6) pour la premire, mais rien pour les deux suivantes. Elle
utilise donc la valeur zro et vous obtenez :
CORRECTS=6 INVALIDES=0 MANQUANTS=0

Vous ne pouvez pas vraiment en vouloir printf, car elle na pas dautres arguments. bash
a effectu sa substitution de paramtres avant lappel printf.
La dclaration des variables en tant que valeurs entires ne suffit pas :
declare -i corrects invalides manquants

Vous devez leur attribuer une valeur.


Une autre manire dviter ce problme consiste placer les arguments entre guillemets
dans linstruction printf :
printf "CORRECTS=%d INVALIDES=%d MANQUANTS=%d\n" "$corrects" "$invalides"
"$manquants"

Ainsi, le premier argument ne disparat pas. Il est remplac par une chane vide et la
ligne printf contient alors les trois arguments attendus :
printf "CORRECTS=%d INVALIDES=%d MANQUANTS=%d\n" "" "6" ""

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19.12. Vrifier la syntaxe dun script bash

499

printf prsente galement un autre comportement trange. Nous venons dexpliquer ce


qui se passe lorsquil manque des arguments, mais, sils sont trop nombreux, printf rpte et rutilise la ligne de format. Vous obtenez plusieurs lignes de sortie alors que vous
nen attendiez quune seule.
Bien entendu, il est possible den faire une utilisation volontaire :
$ dirs
/usr/bin /tmp ~/temp/divers
$ printf "%s\n" $(dirs)
/usr/bin
/tmp
~/temp/divers
$

Linstruction printf prend la pile de rpertoires (la sortie de la commande dirs) et les
affiche un par un sur des lignes diffrentes, en rptant et en rutilisant le format.
En rsum :
1. Initialisez vos variables, en particulier sil sagit de nombres que vous utilisez dans
des instructions printf.
2. Placez des guillemets autour des arguments sils peuvent tre nuls, surtout
lorsquils sont utiliss dans des instructions printf.
3. Vrifiez que le nombre darguments est correct et essayez dimaginer ce que sera la
ligne aprs les substitutions du shell.
4. Si vous navez pas besoin des possibilits de mise en forme offertes par printf (par
exemple, %05d), optez pour de simples instructions echo.

Voir aussi

http://www.opengroup.org/onlinepubs/009695399/functions/printf.html ;

la recette 2.3, Mettre en forme la sortie, page 34 ;

la recette 2.4, crire la sortie sans le saut de ligne, page 35 ;

la recette 15.6, crire une commande echo portable, page 342 ;

la section printf, page 540.

19.12. Vrifier la syntaxe dun script bash


Problme
Vous modifiez un script bash et vous souhaitez vrifier lexactitude de votre syntaxe.

Solution
Utilisez largument -n de bash pour vrifier la syntaxe, idalement aprs chaque enregistrement de vos modifications et obligatoirement avant leur validation dans un systme de gestion de versions :
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

500

Chapitre 19 Bourdes du dbutant

$ bash -n monScript
$
$ echo 'echo "Ligne invalide' >> monScript
$ bash -n monScript
monScript: line 4: unexpected EOF while looking for matching `"'
monScript: line 5: syntax error: unexpected end of file

Discussion
Loption -n nest pas facile trouver dans la page de manuel de bash ou dans toute autre
rfrence, car elle est dcrite dans la commande interne set. Elle est mentionne dans
laffichage de laide (bash --help) pour -D, mais elle nest pas explique. Cette option
demande bash de lire les commandes mais de ne pas les excuter , ce qui permet de
dtecter les erreurs de syntaxe.
Comme pour tout systme de vrification de la syntaxe, les erreurs de logique et celles
de syntaxe des autres commandes appeles par le script ne sont pas identifies.

Voir aussi

man bash ;

bash --help ;

bash -c help set ;

la recette 16.1, Options de dmarrage de bash, page 368.

19.13. Dboguer des scripts


Problme
Vous ne parvenez pas dterminer le comportement de votre script et les raisons de son
dysfonctionnement.

Solution
Ajoutez set -x au dbut du script, ou bien utilisez set -x pour activer xtrace avant un
point problmatique et ensuite set +x pour la dsactiver. Vous pouvez galement vous
servir de linvite $PS4 (voir la recette 16.2, page 368). La commande xtrace fonctionne
galement en mode interactif (voir la recette 16.2, page 368). Voici un script au comportement inattendu :
#!/usr/bin/env bash
# bash Le livre de recettes : bogue
#
set -x

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19.13. Dboguer des scripts

501

resultat=$1
[ $resultat = 1 ] \
&& { echo "Votre rsultat est 1 ; excellent." ; exit 0; } \
|| { echo "Vous avez chou, disparaissez ! " ; exit 120; }

Avant dexcuter ce script, nous fixons et exportons la valeur de linvite PS4. bash ajoute
cette valeur avant chaque commande affiche pendant une trace dexcution (cest--dire, aprs une instruction set -x ) :
$ export PS4='+xtrace $LINENO : '
$ echo $PS4
+xtrace $LINENO :
$ ./bogue
+xtrace 7 : resultat=
+xtrace 9 : '[' = 1 ']'
./bogue: line 9: [: =: unary operator expected
+xtrace 11 : echo 'Vous avez chou, disparaissez ! '
Vous avez chou, disparaissez !
+xtrace 11 : exit 120
$ ./bogue 1
+xtrace 7 : resultat=1
+xtrace 9 : '[' 1 = 1 ']'
+xtrace 10 : echo 'Votre rsultat est 1 ; excellent.'
Votre rsultat est 1 ; excellent.
+xtrace 10 : exit 0
$ ./bogue 2
+xtrace 7 : resultat=2
+xtrace 9 : '[' 2 = 1 ']'
+xtrace 11 : echo 'Vous avez chou, disparaissez ! '
Vous avez chou, disparaissez !
+xtrace 11 : exit 120

Discussion
Vous trouvez peut-tre bizarre dactiver une fonctionnalit avec - et de la dsactiver
avec +, mais cest ainsi que cela fonctionne. De nombreux outils Unix utilisent -n pour
les options et, puisque nous avons besoin dun mcanisme pour dsactiver -x, +x semble naturel.
Depuis bash 3.0, de nouvelles variables facilitent le dbogage : $BASH_ARGC, $BASH_ARGV,
$BASH_SOURCE, $BASH_LINENO, $BASH_SUBSHELL, $BASH_EXECUTION_STRING et
$BASH_COMMAND. Elles compltent les variables bash existantes, comme $LINENO et la variable tableau $FUNCNAME.
xtrace constitue une technique de dbogage trs pratique, mais elle ne remplace pas un
vritable dbogueur. Le projet Bash Debugger (http://bashdb.sourceforge.net/) propose un
code source modifi de bash qui offre des possibilits de dbogage suprieures, ainsi

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

502

Chapitre 19 Bourdes du dbutant

quun systme de notification derreurs amlior. Ce projet dispose, selon ses propres
termes, du dbogueur de code source bash le plus complet jamais crit .

Voir aussi

help set ;

man bash ;

le chapitre 9 du livre Le shell bash, 3e dition de Cameron Newham et Bill Rosenblatt


(ditions OReilly), qui prsente un script shell pour le dbogage dautres scripts ;

la recette 16.1, Options de dmarrage de bash, page 368 ;

la recette 16.2, Personnaliser linvite, page 368 ;

la recette 17.1, Renommer plusieurs fichiers, page 429.

19.14. viter les erreurs commande non


trouve avec les fonctions
Problme
Vous employez dautres langages, comme Perl, qui vous permettent dappeler une fonction dans une partie du code qui se trouve avant la dfinition de la fonction.

Solution
Les scripts shell sont lus et excuts de manire linaire, du dbut la fin. Vous devez
donc dfinir les fonctions avant de pouvoir les utiliser.

Discussion
Certains langages, comme Perl, passent par plusieurs tapes pendant lesquelles lintgralit du script est analyse. Cela permet dcrire du code en plaant main() au dbut
du fichier, les fonctions (ou sous-routines) venant ensuite. loppos, un script shell est
lu en mmoire, puis excut ligne par ligne. Vous ne pouvez donc pas appeler une fonction avant de lavoir dfinie.

Voir aussi

la recette 10.4, Dfinir des fonctions, page 211 ;

la recette 10.5, Utiliser des fonctions : paramtres et valeur de retour, page 213 ;

lannexe C, Analyse de la ligne de commande, page 569.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

19.15. Confondre caractres gnriques du shell et expressions rgulires

503

19.15. Confondre caractres gnriques du shell


et expressions rgulires
Problme
Parfois, vous rencontrez .* ou simplement *. Dautres fois, vous voyez [a-z]*, mais cela
ne signifie pas ce que vous pensez. Vous utilisez des expressions rgulires pour grep et
sed, mais pas avec toutes les commandes de bash. Vous ne comprenez plus rien.

Solution
Arrtez-vous et respirez profondment. Vous tes probablement perdu parce que vous
apprenez trop de choses en mme temps ou parce que vous ne les utilisez pas assez souvent pour vous en souvenir. La pratique a ses mrites.
Pour bash lui-mme, les rgles ne sont pas trop difficiles mmoriser. En effet, la syntaxe des expressions rgulires nest employe quavec loprateur de comparaison =~.
Toutes les autres expressions de bash se servent dune correspondance de motifs.

Discussion
La correspondance de motifs employe par bash sappuie parfois sur les mmes symboles que les expressions rgulires, mais avec des significations diffrentes. Cependant, les
scripts shell contiennent frquemment des commandes qui utilisent des expressions rgulires, comme grep et sed.
Nous avons demand Chet Ramey, le responsable actuel des sources de bash, si loprateur =~ tait bien le seul concern par les expressions rgulires dans bash. Cest confirm. Il nous a galement fourni une liste des diffrentes parties de la syntaxe bash qui
sappuient sur les correspondances de motifs. Bon nombre ont t prsent dans les recettes de ce livre, mais pas toutes. Pour tre exhaustif, voici les utilisations de la correspondance de motifs :

globalisation des noms de fichiers (expansion des noms de chemins) ;

oprateurs == et != pour [[ ;

instructions case ;

traitement de $GLOBIGNORE ;

traitement de $HISTIGNORE ;

${paramtre#[#]mot} ;
${paramtre%[%]mot} ;
${paramtre/motif/chane} ;

plusieurs commandes de readline (glob-expand-word, glob-complete-word, etc.) ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

504

Chapitre 19 Bourdes du dbutant

complete -G et compgen -G ;

complete -X et compgen -X ;

largument `motif` de la commande interne help.

Merci Chet !

Voir aussi

apprenez lire la page de manuel de bash et consultez-la souvent. Elle est longue,
mais complte et prcise. Si vous souhaitez accder une version en ligne de cette
page, ainsi qu dautres documents sur bash, visitez le site http://www.bashcookbook.com qui propose les dernires informations sur bash ;

gardez galement ce livre porte de mains ;

la recette 5.18, Modifier certaines parties dune chane, page 109 ;

la recette 6.6, Tester lgalit, page 124 ;

la recette 6.7, Tester avec des correspondances de motifs, page 126 ;

la recette 6.8, Tester avec des expressions rgulires, page 127 ;

la recette 13.14, Supprimer les espaces, page 277.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

A
Listes de rfrence

Cette annexe runit de nombreux tableaux de rfrence, pour les valeurs, les paramtres, les oprateurs, les commandes, les variables, etc.

Invocation de bash
Voici les options que vous pouvez utiliser lors de linvocation des versions actuelles de
bash. Les options plusieurs caractres doivent apparatre sur la ligne de commande
avant celles un caractre. Les shells douverture de session sont gnralement invoqus
avec les options -i (interactif), -s (lire depuis lentre standard) et -m (activer le contrle
des tches).
Outre celles donnes au tableau A-1, toute option de set peut tre utilise sur la ligne de
commande (voir la section Options de set, page 516). Loption -n est particulirement
utile pour la vrification de la syntaxe (voir la recette 19.12, page 499).
Tableau A-1. Options de la ligne de commande de bash
Option

Signification

-c chane

Les commandes sont lues depuis chane. Les arguments placs


aprs chane sont interprts comme des paramtres positionnels, en commenant $0.

-D

Une liste de toutes les chanes entre guillemets et prcdes de $


est affiche sur la sortie standard. Il sagit des chanes qui seront
sujettes une traduction lorsque la localisation actuelle nest
pas celle de C ni de POSIX. Cette option active galement -n.

-i

Le shell est en mode interactif. Les signaux TERM, INT et QUIT


sont ignors. Lorsque le contrle des tches est actif, TTIN, TTOU
et TSTP sont galement ignors.

-l

bash se comporte comme sil avait t invoqu en tant que shell


douverture de session.

-o option

Attend les mmes arguments que set -o.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

506

Annexe A Listes de rfrence

Tableau A-1. Options de la ligne de commande de bash (suite)


Option

Signification

-O, +O option-shopt

option-shopt est lune des options du shell acceptes par la


commande interne shopt. Si option-shopt est prsent, -O fixe la
valeur de cette option, tandis que +O lannule. Si option-shopt
est absent, les noms et les valeurs des options du shell reconnues par shopt sont affichs sur la sortie standard. Si loption
dinvocation est +O, la sortie est affiche dans un format qui lui
permet dtre rutilise en entre.

-s

Les commandes sont lues depuis lentre standard. Si un argument est pass bash, cette option est prioritaire (autrement dit,
largument nest pas trait comme un nom de script et lentre
standard est lue).

-r

Le shell fonctionne en mode restreint.

-v

Les lignes dentre du shell sont affiches au fur et mesure de


leur lecture.

--

Indique la fin des options et dsactive le traitement dventuelles options supplmentaires. Les options places aprs celle-ci
sont traites comme des noms de fichiers et des arguments.
-- est synonyme de -.

--debugger

Le profil du dbogueur est excut avant le dmarrage du shell.


Le mode de dbogage tendu et la trace des fonctions shell sont
activs dans bash 3.0 et les versions ultrieures.

--dump-strings

Identique -D.

--dump-po-strings

Identique -D, mais la sortie est au format de fichier dobjet


portable (po) de GNU gettext.

--help

Affiche un message dutilisation et se termine.

--login

bash se comporte comme sil avait t invoqu en tant que shell


douverture de session. Identique -l.

--noediting

La bibliothque readline de GNU nest pas utilise pour lire les


lignes de commandes en mode interactif.

--noprofile

Le fichier de dmarrage /etc/profile nest pas lu, tout comme les


fichiers dinitialisation personnels.

--norc

Le fichier dinitialisation ~/.bashrc nest pas lu si le shell est en


mode interactif. Il sagit du comportement par dfaut si le shell
est invoqu en temps que sh.

--posix

Le comportement de bash suit plus troitement la norme


POSIX l o son fonctionnement par dfaut est diffrent.

--quiet

Aucune information nest affiche au dmarrage du shell. Il


sagit du comportement par dfaut.

--rcfile fichier,
--init-file fichier

En mode interactif, bash excute les commandes lues depuis


fichier la place du fichier dinitialisation ~/.bashrc.

--verbose

quivalent -v.

--version

Affiche le numro de version de cette instance de bash et se termine.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Personnaliser les chanes dinvite

507

Personnaliser les chanes dinvite


Le tableau A-2 rcapitule les possibilits de personnalisation de linvite. Les commandes
\[ et \] sont disponibles dans bash 1.14+. \a, \e, \H, \T, \@, \v et \V sont disponibles dans
les versions 2.0 et ultrieures. \A, \D, \j, \l et \r ne seront prsentes que dans les versions suprieures de bash 2.0 et dans bash 3.0.
Tableau A-2. Codes de format pour les chanes dinvite
Commande

Signification

Disponibilit

\a

Le caractre ASCII de la sonnerie (007).

bash-1.14.7

\A

Lheure actuelle au format HH:MM sur 24 heures.

bash-2.05

\d

La date au format Jour-de-la-semaine Mois Jour .

\D {format}

Le format est pass strftime(3) et le rsultat est insr bash-2.05b


dans la chane dinvite. Un format vide produit une
reprsentation de lheure conformment aux paramtres rgionaux. Les accolades sont obligatoires.

\e

Le caractre ASCII dchappement (033).

bash-1.14.7

\H

Le nom dhte.

bash-1.14.7

\h

Le nom dhte jusquau premier . .

\j

Le nombre de tches actuellement gres par le shell.

\l

La base du nom du priphrique de terminal du shell. bash-2.03

\n

Un retour chariot et un saut de ligne.

\r

Un retour chariot.

\s

Le nom du shell.

\T

Lheure actuelle au format HH:MM:SS sur 12 heures.

\t

Lheure actuelle au format HH:MM:SS.

\@

Lheure actuelle au format a.m./p.m. sur 12 heures.

\u

Le nom de lutilisateur courant.

\v

Le numro de version de bash (par exemple, 2.00).

\V

Le numro de version complet de bash ; la version et bash-1.14.7


le niveau de correctif (par exemple, 3.00.0).

\w

Le rpertoire de travail.

\W

Le nom de base du rpertoire de travail.

\#

Le numro de la commande en cours.

\!

Le numro dhistorique de la commande.

\$

Si lUID rel est 0, afficher #, sinon afficher $.

\nnn

Le caractre correspondant au code en octal.

\\

La barre oblique inverse.

\[

Dbut dune suite de caractres non imprimables,


comme des squences de contrle du terminal.

\]

Fin dune suite de caractres non imprimables.

[05/03/08]

bash Le livre de recettes

bash-2.03

bash-2.01.1
bash-1.14.7
bash-1.14.7
bash-1.14.7

Elodie FRITSCH <elodie.fritsch@total.com>

508

Annexe A Listes de rfrence

Squences dchappement ANSI pour la couleur


Le tableau A-3 prsente les squences dchappement ANSI qui permettent de contrler
les couleurs daffichage.
Tableau A-3. Squences dchappement ANSI pour la couleur
Code

Attribut de
caractre

Code
Couleur
Code
Couleur
davant-plan davant-plan darrire-plan darrire-plan

Rinitialisation

30

Noir

40

Noir

Clair

31

Rouge

41

Rouge

Fonc

32

Vert

42

Vert

Soulign

33

Jaune

43

Jaune

Clignotant

34

Bleu

44

Bleu

Invers

35

Magenta

45

Magenta

Masqu

36

Cyan

46

Cyan

37

Blanc

47

Blanc

Commandes internes et mots rservs


Le tableau A-4 prsente toutes les commandes internes et les mots rservs. Voici la signification de la colonne Type : R = mot rserv, vide = commande interne.
Tableau A-4. Commandes internes et mots rservs
Commande

Type

Description

NON logique du code de sortie dune commande.

Ne fait rien (uniquement lexpansion des arguments).

Lire un fichier et excuter ses commandes dans le shell en


cours.

alias

Dfinir un raccourci pour une commande ou une ligne de


commande.

bg

Placer la tche en arrire-plan.

bind

Lier une squence de touches une fonction ou une macro


readline.

break

Quitter la boucle for, select, while ou until englobante.


Excuter la commande interne indique.

builtin
case

Construction conditionnelle choix multiples.

cd

Changer de rpertoire de travail.

command

Excuter une commande en contournant la recherche des


fonctions.

compgen

Gnrer les compltions possibles.

complete

Prciser le fonctionnement de la compltion.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Commandes internes et mots rservs

509

Tableau A-4. Commandes internes et mots rservs (suite)


Commande

Type

continue

Passer litration suivante de la boucle for, select, while ou


until.

declare

Dclarer des variables et leur donner des attributs. Identique


typeset.

dirs

Afficher la liste des rpertoires actuellement mmoriss.


Supprimer une tche du tableau de tches.

disown
do

done

lment dune construction for, select, while ou until.


lment dune construction for, select, while ou until.
Afficher les arguments.

echo
elif

lment dune construction if.

else

lment dune construction if.


Activer et dsactiver des commandes internes.

enable
esac

Fin dune construction case.

eval

Passer les arguments indiqus au traitement de la ligne de


commande.

exec

Remplacer le shell par le programme indiqu.

exit

Quitter le shell.

export

Crer des variables denvironnement.

fc

Corriger une commande (modifier le fichier dhistorique).


Passer une tche au premier plan.

fg
fi

lment dune construction if.

for

Construction de boucle.

function

Dfinir une fonction.

getopts

Traiter les options de la ligne de commande.

hash

Les noms de chemins complets sont dtermins et mmoriss.

help

Afficher des informations sur des commandes internes.

history

Afficher lhistorique des commandes.

if

Construction conditionnelle.

in

lment dune construction case.

jobs

Afficher les tches en arrire-plan.

kill

Envoyer un signal un processus.

let

Affecter des variables arithmtiques.

local

Crer une variable locale.

logout

Quitter un shell douverture de session.

popd

Retirer un rpertoire de la pile.

pushd

Ajouter un rpertoire la pile.

pwd

Afficher le rpertoire de travail.

[05/03/08]

bash Le livre de recettes

Description

Elodie FRITSCH <elodie.fritsch@total.com>

510

Annexe A Listes de rfrence

Tableau A-4. Commandes internes et mots rservs (suite)


Commande

Type

Description

read

Lire une ligne depuis lentre standard.

readonly

Dfinir des variables en lecture seule (non modifiables).


Sortir de la fonction ou du script englobant.

return
select

Construction de menus.

set

Fixer des options.

shift

Dcaler les arguments de la ligne de commande.

suspend

Suspendre lexcution dun shell.

test

valuer une expression conditionnelle.

then

lment dune construction if.

time

Excuter un tube de commandes et afficher la dure de lexcution. Le format de la sortie peut tre dfini dans la variable
TIMEFORMAT.

times

Afficher le cumul des temps utilisateur et systme pour les


processus excuts partir du shell.

trap

Dfinir un gestionnaire de signal.

type

Identifier la source dune commande.

typeset

Dclarer des variables et leur donner des attributs. Identique


declare.

ulimit

Fixer/afficher les limites de ressources de processus.

umask

Fixer/afficher le masque des autorisations de fichiers.

unalias

Supprimer les dfinitions dalias.

unset

Supprimer les dfinitions de variables ou de fonctions.

until

while

Construction de boucle.
Attendre la fin dune ou plusieurs tches en arrire-plan.

wait
R

Construction de boucle.

Variables internes
Le tableau A-5 donne la liste complte des variables denvironnement disponibles dans
bash 3.0. Voici la signification de la colonne Type : L = liste spare par des deux-points,
R = en lecture seule, T = tableau, U = sa rinitiaisation lui fait perdre sa signification spciale.
Notez que les variables qui commencent par BASH_ ou par COMP, ainsi que les variables
DIRSTACK, FUNCNAME, GLOBIGNORE, GROUPS, HISTIGNORE, HOSTNAME, HISTTIMEFORMAT, LANG,
LC_ALL, LC_COLLATE, LC_MESSAGE, MACHTYPE, PIPESTATUS, SHELLOPTS et TIMEFORMAT ne
sont pas disponibles dans les versions antrieures la 2.0. BASH_ENV remplace ENV qui
existait dans les versions antrieures.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Variables internes

511

Tableau A-5. Variables denvironnement internes au shell


Variable

Type

Description

Une chane contenant les paramtres positionnels passs au


script ou la fonction. Les paramtres sont spars par le
premier caractre de la variable $IFS (par exemple, arg1
arg2 arg3).

Chacun des paramtres positionnels passs au script ou la


fonction, donns sous forme dune liste de chanes entre
guillemets (par exemple, "arg1" "arg2" "arg3").

Le nombre darguments passs au script ou la fonction.

Les options passes lors de linvocation du shell.

Le code de sortie de la commande prcdente.

Le dernier argument de la commande prcdente.

Lidentifiant du processus du shell.

Lidentifiant du processus de la dernire commande en


arrire-plan.

Le nom du shell ou du script.


Le nom de chemin complet utilis pour invoquer cette instance de bash.

BASH
BASH_ARGC

Un tableau de valeurs qui correspondent au nombre de


paramtres de chaque trame de la pile dappels dexcution
du bash courant. Le nombre de paramtres passs la sousroutine en cours (fonction ou script shell excut avec . ou
source) se trouve au sommet de la pile.

BASH_ARGV

Tous les paramtres de la pile dappel dexcution du bash


courant. Le dernier paramtre du dernier appel de sous-routine se trouve au sommet de la pile. Le premier paramtre
de lappel initial se trouve la fin.

BASH_COMMAND

La commande en cours dexcution ou sur le point dtre


excute, moins que le shell nexcute une commande
suite une capture, auquel cas il sagit de la commande qui
sexcutait au moment de la capture.

BASH_EXECUTION_
STRING

Largument de loption dinvocation -c.

BASH_ENV

Le nom dun fichier dfinissant lenvironnement excuter


lors de linvocation du shell.

BASH_LINENO

[05/03/08]

bash Le livre de recettes

Un tableau dont les lments sont les numros de ligne des


fichiers sources correspondant chaque lment de
@var{FUNCNAME}. ${BASHLINENO[$i]} est le numro de ligne
dans le fichier source o ${FUNCNAME[$i + 1]} a t appele. Le nom du fichier source correspondant est ${BASHSOURCE[$i + 1]}.

Elodie FRITSCH <elodie.fritsch@total.com>

512

Annexe A Listes de rfrence

Tableau A-5. Variables denvironnement internes au shell (suite)


Variable

Type

Description

BASH_REMATCH

RT

Un tableau dont les lments sont affects avec loprateur


binaire =~ dans la commande conditionnelle [[. Llment
dindice 0 est la partie de la chane qui correspond lexpression rgulire complte. Llment dindice n est la partie de
la chane qui correspond la nme sous-expression entre
parenthses.

BASH_SOURCE

Un tableau contenant les noms des fichiers sources qui correspondent aux lments de la variable tableau $FUNCNAME.
Cette variable est incrmente de 1 chaque cration dun
sous-shell ou dun environnement de sous-shell. La valeur
initiale est 0. Un sous-shell est une copie du shell parent et il
partage son environnement.

BASH_SUBSHELL

Le numro de version de cette instance de bash.

BASH_VERSION
BASH_VERSINFO

RT

Les informations de version de cette instance de bash. Chaque lment du tableau dtient une partie du numro de
version.

CDPATH

Une liste des rpertoires recherchs par la commande cd.

COMP_CWORD

Un indice dans ${COMPWORDS} du mot contenant la position


actuelle du curseur. Cette variable nest disponible que dans
les fonctions shell invoques par les outils de compltion
programmable.

COMP_LINE

La ligne de commande en cours. Cette variable nest disponible que dans les fonctions shell et les commandes externes
invoques par les outils de compltion programmable.

COMP_POINT

Lindice de la position actuelle du curseur relativement au


dbut de la commande courante. Si le curseur se trouve la
fin de la commande en cours, la valeur de cette variable est
gale ${#COMPLINE}. Cette variable nest disponible que
dans les fonctions shell et les commandes externes invoques par les outils de compltion programmable.

COMP_WORDBREAKS

Lensemble des caractres considrs par la bibliothque


Readline comme des sparateurs de mots lors de la compltion des mots. Si COMP_WORDBREAKS est dsaffecte, elle perd
sa signification spciale, mme si elle est rinitialise ultrieurement.

COMP_WORDS

Un tableau des mots de la ligne de commande en cours.


Cette variable nest disponible que dans les fonctions shell
invoques par les outils de compltion programmable.

COMPREPLY

Les compltions possibles gnres par une fonction shell


invoque par les outils de compltion programmable.

DIRSTACK

RTU

Le contenu actuel de la pile de rpertoires.

EUID

Lidentifiant dutilisateur rel de lutilisateur connect.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Variables internes

513

Tableau A-5. Variables denvironnement internes au shell (suite)


Variable

Type

Description

FUNCNAME

RTU

Un tableau contenant les noms de toutes les fonctions shell


actuellement dans la pile dappels dexcution. Llment
dindice 0 correspond au nom de la fonction en cours dexcution. Le dernier lment correspond main. Cette variable existe uniquement pendant lexcution dune fonction
shell.
Lditeur par dfaut de la commande fc.

FCEDIT
FIGNORE

La liste des noms ignorer lors de la compltion des noms


de fichiers.

GLOBIGNORE

La liste des motifs dfinissant les noms de fichiers ignorer


lors de lexpansion des noms de chemins.

GROUPS

RT

Un tableau contenant la liste des groupes dont lutilisateur


courant est membre.
Le sparateur de champs interne (Internal Field Separator) :
une liste des caractres qui servent de sparateurs de mots.
Elle contient par dfaut une espace, une tabulation et un
saut de ligne.

IFS

HISTCMD

Le numro dhistorique de la commande en cours.


Une liste de motifs, spars par des deux-points (:), qui peuvent avoir les valeurs suivantes : ignorespace (les lignes
commenant par une espace ne sont pas ajoutes lhistorique), ignoredups (les lignes correspondant la dernire
ligne de lhistorique ne sont pas ajoutes), erasedups (toutes les lignes prcdentes correspondant la ligne actuelle
sont retires de lhistorique avant que celle-ci soit ajoute) et
ignoreboth (active ignorespace et ignoredups).

HISTFILE

Le nom du fichier dhistorique des commandes.

HISTIGNORE

Une liste de motifs qui dterminent ce qui entre dans lhistorique.

HISTSIZE

Le nombre de lignes conserves dans lhistorique des commandes.

HISTFILESIZE

Le nombre maximum de lignes conserves dans le fichier


dhistorique.

HISTTIMEFORMAT

Lorsquelle est dfinie et non nulle, sa valeur est utilise


comme chane de format strftime(3) pour laffichage de
lestampille temporelle associe chaque rentre dhistorique prsente par la commande history. Si cette variable est
dfinie, les estampilles temporelles sont crites dans le
fichier dhistorique afin dtre conserves entre les sessions
du shell.

HOME

Le rpertoire personnel (daccueil).

HOSTFILE

Le fichier utilis pour la compltion des noms dhtes.

[05/03/08]

bash Le livre de recettes

HISTCONTROL

Elodie FRITSCH <elodie.fritsch@total.com>

514

Annexe A Listes de rfrence

Tableau A-5. Variables denvironnement internes au shell (suite)


Variable

Type

HOSTNAME

Le nom de lhte courant.

HOSTTYPE

Le type de machine sur laquelle sexcute bash.

IGNOREEOF

Le nombre de caractres EOF reus avant de clore un shell


interactif.

INPUTRC

Le fichier de dmarrage de readline.

LANG

Utilise pour dterminer les paramtres rgionaux de toute


catgorie non spcifiquement choisie par une variable commenant par LC_.

LC_ALL

Supplante la valeur de $LANG et de toute autre variable LC_


qui prcise une catgorie de paramtres rgionaux.

LC_COLLATE

Dtermine lordre de rassemblement employ lors du tri des


rsultats dune expansion de noms de chemins.

LC_CTYPE

Dtermine linterprtation des caractres et le comportement des classes de caractres dans lexpansion des noms de
chemins et la correspondance de motifs.

LC_MESSAGES

Dtermine les paramtres rgionaux servant la traduction


des chanes entre guillemets prcdes dun symbole $.

LC_NUMERIC

Dtermine les paramtres rgionaux servant la mise en


forme des nombres.

LINENO

Le numro de la ligne qui vient dtre excute dans un


script ou une fonction.

MACHTYPE

Une chane qui dcrit le systme sur lequel bash sexcute.

MAIL

Le nom du fichier consulter pour dterminer larrive


dun nouveau message lectronique.

MAILCHECK

Lintervalle (en secondes) de vrification de larrive dun


nouveau message lectronique.

MAILPATH

La liste des noms de fichiers consulter pour dterminer


larrive dun nouveau message lectronique, si $MAIL nest
pas dfinie.

OLDPWD

Le rpertoire de travail prcdent.

OPTARG

La valeur du dernier argument doption trait par getopts.

OPTERR

Si elle vaut 1, les messages derreur de getopts sont affichs.

OPTIND

Le numro du premier argument aprs les options.


Le systme dexploitation sur lequel bash sexcute.

OSTYPE
PATH

Le chemin de recherche des commandes.

PIPESTATUS

Une variable tableau contenant la liste des codes de sortie


des processus impliqus dans le dernier tube excut au premier plan.

[05/03/08]

bash Le livre de recettes

Description

Elodie FRITSCH <elodie.fritsch@total.com>

Variables internes

515

Tableau A-5. Variables denvironnement internes au shell (suite)


Variable

Type

POSIXLY_CORRECT

Si cette variable existe dans lenvironnement au dmarrage


de bash, linterprteur de commandes entre en mode POSIX
avant de lire les fichiers de dmarrage, comme si loption
--posix avait t fournie lors de linvocation. Si elle est
fixe pendant lexcution du shell, bash active le mode
POSIX, comme si la commande set -o posix avait t invoque.

PROMPT_COMMAND

Sa valeur est excute comme une commande avant laffichage de linvite principale.

PS1

La chane de linvite principale.

PS2

La chane de linvite pour les continuations de ligne.

PS3

La chane de linvite de la commande select.

PS4

La chane de linvite de loption xtrace.

PPID

RANDOM

Le nombre de secondes coules depuis linvocation du


shell.

LR

La liste des options du shell actives.

Le nom de chemin complet du shell.

SHELL
SHELLOPTS

Un nombre alatoire entre 0 et 32 767 (215 - 1).


La rponse de lutilisateur la commande select. Le rsultat
de la commande read si aucun nom de variable na t prcis.

REPLY

SECONDS

Lidentifiant du processus parent.


Le rpertoire de travail.

PWD

SHLVL

Incrmente de 1 chaque fois quune nouvelle instance (et


non un sous-shell) de bash est invoque. Elle permet de connatre le niveau dimbrication des shells bash.

TIMEFORMAT

Prcise le format de sortie du mot rserv time dans un tube


de commandes.

TMOUT

Fixe un entier positif, elle indique le nombre de secondes


aprs lequel le shell se termine automatiquement en
labsence de saisie.

UID

Lidentifiant de lutilisateur courant.

auto_resume

Dtermine le fonctionnement du contrle des tches (les


valeurs sont exact, substring ou autre chose que ces motscls).

histchars

Prcise les caractres de contrle de lhistorique. Par dfaut,


il sagit de la chane !^#.

[05/03/08]

bash Le livre de recettes

Description

Elodie FRITSCH <elodie.fritsch@total.com>

516

Annexe A Listes de rfrence

Options de set
Les options donnes au tableau A-6 peuvent tre actives laide de la commande set
-arg. Elles sont toutes inactives par dfaut, sauf mention contraire. Les noms complets,
lorsquils sont indiqus, sont des arguments de set qui peuvent tre utiliss avec set -o.
Les noms complets braceexpand, histexpand, history, keyword et onecmd ne sont pas
disponibles dans les versions de bash antrieures la 2.0. Dans ces versions, le hachage
est configur avec -d.
Tableau A-6. Options de set
Option

Nom complet (-o)

Signification

-a

allexport

Exporter toutes les variables dfinies ou modifies par la


suite.

-B

braceexpand

Le shell effectue lexpansion des crochets. Elle est active


par dfaut.

-b

notify

Afficher immdiatement le code de sortie des tches


darrire-plan qui se terminent.

-C

noclobber

Interdire le remplacement des fichiers existants par la


redirection.

-E

errtrace

Toute capture de ERR est hrite par les fonctions shell,


les substitutions de commandes et les commandes excutes dans un sous-shell.

-e

errexit

Quitter le shell lorsquune commande simple se termine


avec un code de sortie diffrent de zro. Une commande
simple est une commande qui ne fait pas partie dune
construction while, until ou if, ni dune liste && ou ||,
ni une commande dont la valeur de retour est inverse
par !.

emacs

Utiliser ldition de la ligne de commande de type Emacs.

-f

noglob

Dsactiver lexpansion du nom de chemin.

-H

histexpand

Activer la substitution dhistorique avec !. Elle est active


par dfaut dans les shells interactifs.

history

Activer lhistorique des commandes. Elle est active par


dfaut dans les shells interactifs.

hashall

Activer le hachage des commandes.

ignoreeof

Interdire la sortie du shell par Ctrl-D.

-k

keyword

Tous les arguments sous la forme daffectations sont placs dans lenvironnement dune commande et non pas
uniquement ceux qui prcdent le nom de la commande.

-m

monitor

Activer le contrle des tches. Elle est active par dfaut


dans les shells interactifs.

-n

noexec

Lire des commandes et vrifier leur syntaxe, mais ne pas


les excuter. Elle est ignore dans les shells interactifs.

-h

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Options de shopt

517

Tableau A-6. Options de set (suite)


Option

Nom complet (-o)

Signification

-P

physical

Ne pas suivre les liens symboliques dans les commandes


qui changent le rpertoire de travail. Utiliser le rpertoire physique.

-p

privileged

Le script sexcute en mode privilgi (suid).

pipefail

La valeur de retour dun tube est celle de la dernire


commande qui se termine avec un code dtat diffrent
de zro ou bien zro si toutes les commandes du tube se
terminent avec succs. Elle est dsactive par dfaut.

posix

Changer le comportement afin quil se conforme la


norme POSIX 1003.2 l o ce nest pas le cas par dfaut.

-T

functrace

Toute capture de DEBUG est hrite par les fonctions shell,


les substitutions de commandes et les commandes excutes dans un sous-shell.

-t

onecmd

Quitter aprs avoir lu et excut une commande.

-u

nounset

Considrer les variables non dfinies comme des erreurs


et non comme nulles.

-v

verbose

Afficher les lignes dentre du shell avant de les excuter.

vi

Utiliser ldition de la ligne de commande de type vi.

xtrace

Afficher les commandes, aprs les expansions, avant de


les excuter.

-x
-

Marquer la fin des options. Tous les arguments restants


sont affects aux paramtres positionnels. -x et -v sont
dsactives. Sil ny a pas dautres arguments set, les
paramtres positionnels restent inchangs.

--

Sans autre argument, les paramtres positionnels sont


indfinis. Sinon, ils prennent la valeur des arguments suivants (mme sils commencent par -).

Options de shopt
Les options de shopt sont fixes par la commande shopt -s arg et indfinies par shopt
-u arg (voir le tableau A-7). Les versions de bash antrieures la 2.0 disposent de variables
denvironnement qui jouent le rle de certains de ces paramtres ; les fixer quivaut
shopt -s. Les variables (et les options correspondantes de shopt) taient : allow_null_
glob_expansion (nullglob), cdable_vars (cdable_vars), command_oriented_history
(cmdhist), glob_dot_filenames (dotglob) et no_exit_on_failed_exec (execfail). Ces
variables nexistent plus.
Les options extdebug, failglob, force_fignore et gnu_errfmt sont disponibles depuis
bash 3.0.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

518

Annexe A Listes de rfrence

Tableau A-7. Options de shopt


Option

Signification si dfinie

cdable_vars

Lorsquun argument de cd nest pas un rpertoire, il est considr comme un nom de variable qui contient le rpertoire
cible.

cdspell

Les petites erreurs dcriture du rpertoire fourni la commande cd seront corriges si une correspondance existe.
Cette correction concerne les lettres manquantes, les lettres
incorrectes et les inversions de lettres. Elle fonctionne uniquement dans les shells interactifs.

checkhash

Avant dexcuter les commandes qui se trouvent dans la


table de hachage, leur existence est vrifie et leur absence
conduit une recherche dans les rpertoires de $PATH.

checkwinsize

Vrifier la taille de la fentre aprs chaque commande et, si


elle a chang, actualiser les variables $LINES et $COLUMNS en
consquence.

cmdhist

Tenter denregistrer toutes les lignes dune commande sur


plusieurs lignes dans une mme entre de lhistorique.

dotglob

Les noms de fichiers qui commencent par un . sont pris en


compte lors de lexpansion du nom de chemin.

execfail

Un shell non interactif ne se terminera pas sil ne peut pas


excuter largument dune commande exec. Les shells interactifs ne se terminent pas en cas dchec de exec.

expand_aliases

Les alias sont dvelopps.

extdebug

Le comportement destin aux dbogueurs est activ :


loption -F de declare affiche le nom du fichier source et le
numro de ligne correspondant chaque nom de fonction
pass en argument, si la commande excute par le gestionnaire de DEBUG retourne une valeur diffrente de zro alors
la commande suivante est saute et non excute, et si la
commande excute par le gestionnaire de DEBUG retourne
la valeur 2 et si le shell se trouve dans une sous-routine alors
un appel return est simul.

extglob

Les fonctions de correspondance de motifs tendue sont


actives.

failglob

Les motifs qui ne correspondent aucun nom de fichier


pendant lexpansion du nom de chemin gnrent une
erreur dexpansion.

force_fignore

Les suffixes indiqus par la variable shell $FIGNORE conduisent la compltion de mots en ignorer certains, mme si
ces mots ignors sont les seules compltions possibles.

gnu_errfmt

Les messages derreurs du shell sont affichs en respectant le


format standard de GNU.

histappend

Lhistorique est ajout au fichier indiqu par la valeur de la


variable $HISTFILE lorsque le shell se termine, au lieu
dcraser le fichier.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Options de shopt

519

Tableau A-7. Options de shopt (suite)


Option

Signification si dfinie

histreedit

Si readline est utilise, il est possible de remodifier une substitution dhistorique qui a chou.

histverify

Si readline est utilise, les rsultats de la substitution dhistorique ne sont pas immdiatement passs lanalyseur du
shell. la place, la ligne rsultante est charge dans le tampon ddition de readline afin quelle puisse tre modifie si
ncessaire.

hostcomplete

Si readline est utilise, une compltion de nom dhte sera


tente lorsquun mot commence par @.

huponexit

bash envoie SIGHUP toutes les tches lors de la terminaison


dun shell douverture de session interactif.

interactive_comments

Accepter les mots commenant par #, en ignorant tous les


caractres suivants de la ligne, dans un shell interactif.

lithist

Si loption cmdhist est active, les commandes sur plusieurs


lignes sont enregistres dans lhistorique en remplaant les
points-virgules par des sauts de ligne, lorsque cest possible.

login_shell

Indique que bash a t dmarr comme un shell douverture


de session. Cette valeur est en lecture seule.

mailwarn

Si le fichier consult pour dterminer larrive de messages


a t manipul depuis la dernire vrification, le message
The mail in fichier_de_courrier has been read est affich.

no_empty_cmd_completion

Si readline est utilise, la variable PATH nest pas consulte


pour trouver les compltions possibles lorsque la ligne est
vide.

nocaseglob

La compilation des noms de chemins se fait de manire


insensible la casse.

nullglob

Les motifs qui ne correspondent aucun fichier sont remplacs par des chanes nulles et non par eux-mmes.

progcomp

Les outils de compltion programmable sont activs. Cest le


cas par dfaut.

promptvars

Les chanes dinvite sont sujettes lexpansion des variables


et des paramtres aprs avoir t dveloppes.

restricted_shell

Indique si le shell a t dmarr en mode restreint. Cette


valeur est en lecture seule.

shift_verbose

La commande interne shift affiche une erreur lorsque le


dcalage dpasse le dernier paramtre positionnel.

sourcepath

La commande interne source utilise la valeur de $PATH pour


trouver le rpertoire qui contient le fichier fourni en argument.

xpg_echo

echo dveloppe par dfaut les squences dchappement


base de barre oblique inverse.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

520

Annexe A Listes de rfrence

Ajuster le comportement du shell avec set,


shopt et les variables
Le tableau A-8 combine les tableaux A-5, A-6 et A-7 pour que vous puissiez trouver rapidement les possibilits de configuration et le mcanisme qui permet de les mettre en
uvre. Les options sont regroupes par fonction ou objectif, mais il nest pas inutile de
parcourir lintgralit du tableau pour avoir une connaissance gnrale des aspects configurables.
La colonne Option de set contient les options pouvant tre actives laide de la commande set -arg. Initialement, elles sont toutes inactives, sauf mention contraire. Le contenu de la colonne Nom complet de set prsente les arguments de set qui peuvent
tre employs avec set -o. Les noms complets braceexpand, histexpand, history, keyword et onecmd ne sont disponibles qu partir de bash version 2.0. Dans les versions antrieures, le hachage est obtenu avec -d.
La colonne Option de shopt donne les options fixes avec shopt -s arg et indfinies
avec shopt -u arg. Les versions de bash antrieures la 2.0 disposent de variables denvironnement pour certaines de ses configurations. Elles ont le mme rle que shopt -s.
Ces
variables
(et
les
options
correspondantes
de
shopt)
taient :
allow_null_glob_expansion
(nullglob),
cdable_vars
(cdable_vars),
command_oriented_history
(cmdhist),
glob_dot_filenames
(dotglob)
et
no_exit_on_failed_exec (execfail). Elles nexistent plus.
Les options extdebug, failglob, force_fignore et gnu_errfmt sont disponibles dans
bash 3.0+.
La colonne Variable denvironnement prsente les variables ayant un impact sur la
configuration et le fonctionnement de bash. Voici la signification des lettres de la colonne Type : L = liste spare par des deux-points, R = en lecture seule, T = tableau, U =
sa rinitiaisation lui fait perdre sa signification spciale.
Notez que les variables qui commencent par BASH_ ou par COMP, ainsi que les variables
DIRSTACK, FUNCNAME, GLOBIGNORE, GROUPS, HISTIGNORE, HOSTNAME, HISTTIMEFORMAT, LANG,
LC_ALL, LC_COLLATE, LC_MESSAGE, MACHTYPE, PIPESTATUS, SHELLOPTS et TIMEFORMAT ne
sont pas disponibles dans les versions antrieures bash 2.0. BASH_ENV remplace ENV qui
existait dans les versions antrieures.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Option
de set

Nom complet
de set
Option de shopt

[05/03/08]

Lensemble des caractres considrs par la bibliothque


Readline comme des sparateurs de mots lors de la compltion des mots. Si COMP_WORDBREAKS est dsaffecte, elle
perd sa signification spciale, mme si elle est rinitialise
ultrieurement.
Un tableau des mots de la ligne de commande en cours.
Cette variable nest disponible que dans les fonctions shell
invoques par les outils de compltion programmable.
Les compltions possibles gnres par une fonction shell
invoque par les outils de compltion programmable.
La liste des noms ignorer lors de la compltion des noms
de fichiers.

T
L

COMP_WORDS

COMPREPLY
FIGNORE

Lindice de la position actuelle du curseur relativement au


dbut de la commande courante. Si le curseur se trouve
la fin de la commande en cours, la valeur de cette variable
est gale ${#COMPLINE}. Cette variable nest disponible
que dans les fonctions shell et les commandes externes
invoques par les outils de compltion programmable.

COMP_POINT

COMP_WORDBREAKS

La ligne de commande en cours. Cette variable nest disponible que dans les fonctions shell et les commandes externes invoques par les outils de compltion programmable.

COMP_LINE

Description
Un indice dans ${COMPWORDS} du mot contenant la position actuelle du curseur. Cette variable nest disponible
que dans les fonctions shell invoques par les outils de
compltion programmable.

Type var.
denv.

COMP_CWORD

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables

Ajuster le comportement du shell avec set, shopt et les variables


521

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

noclobber

onecmd

physical

-t

-P

Nom complet
de set

-C

Option
de set

sourcepath

restricted_shell
SHELLOPTS

LR

La commande interne source utilise la valeur de $PATH


pour trouver le rpertoire qui contient le fichier fourni en
argument.

La liste des options du shell actives.

Indique si le shell a t dmarr en mode restreint. Cette


valeur est en lecture seule.

Ne pas suivre les liens symboliques dans les commandes


qui changent le rpertoire de travail. Utiliser le rpertoire
physique.

Quitter aprs avoir lu et excut une commande.

Interdire le remplacement des fichiers existants par la redirection.

Le fichier de dmarrage de readline.

Les outils de compltion programmable sont activs. Cest


le cas par dfaut.

progcomp
INPUTRC

Si readline est utilise, la variable PATH nest pas consulte


pour trouver les compltions possibles lorsque la ligne est
vide.

Le fichier utilis pour la compltion des noms dhtes.

no_empty_
cmd_completion

HOSTFILE

Si readline est utilise, une compltion de nom dhte sera


tente lorsquun mot commence par @.

Description

hostcomplete

Type var.
denv.
Les suffixes indiqus par la variable shell $FIGNORE conduisent la compltion de mots en ignorer certains, mme si
ces mots ignors sont les seules compltions possibles.

Variable denvironnement

force_fignore

Option de shopt

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

522
Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

-E

Option
de set

errtrace

Nom complet
de set
Option de shopt

Un tableau contenant les noms des fichiers sources qui


correspondent aux lments de la variable tableau $FUNCNAME.

BASH_SOURCE

Toute capture de ERR est hrite par les fonctions shell, les
substitutions de commandes et les commandes excutes
dans un sous-shell.

Un tableau dont les lments sont les numros de ligne


des fichiers sources correspondant chaque lment de
@var{FUNCNAME}. ${BASHLINENO[$i]} est le numro de
ligne dans le fichier source o ${FUNCNAME[$i + 1]} a t
appele. Le nom du fichier source correspondant est
${BASHSOURCE[$i + 1]}.

BASH_LINENO

La commande en cours dexcution ou sur le point dtre


excute, moins que le shell nexcute une commande
suite une capture, auquel cas il sagit de la commande
signe qui sexcutait au moment de la capture.

Tous les paramtres de la pile dappel dexcution du bash


courant. Le dernier paramtre du dernier appel de sousroutine se trouve au sommet de la pile. Le premier paramtre de lappel initial se trouve la fin.

BASH_ARGV

BASH_COMMAND

Un tableau de valeurs qui correspondent au nombre de


paramtres de chaque trame de la pile dappels dexcution du bash courant. Le nombre des paramtres passs
la sous-routine en cours (fonction ou script shell excut
avec . ou source) se trouve au sommet de la pile.

BASH_ARGC

Description

Type var.
denv.

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

Ajuster le comportement du shell avec set, shopt et les variables


523

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

functrace

noexec

verbose

xtrace

-n

-v

-x

Nom complet
de set

-T

Option
de set
extdebug

Option de shopt

LINENO

FUNCNAME

Variable denvironnement

RTU

Type var.
denv.

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

Afficher les commandes, aprs les expansion, avant de les


excuter.

Afficher les lignes dentre du shell avant de les excuter.

Lire des commandes et vrifier la syntaxe, mais ne pas les


excuter. Elle est ignore dans les shells interactifs.

Le numro de la ligne qui vient dtre excute dans un


script ou une fonction.

Toute capture de DEBUG est hrite par les fonctions shell,


les substitutions de commandes et les commandes excutes dans un sous-shell.

Un tableau contenant les noms de toutes les fonctions


shell actuellement dans la pile dappels dexcution. Llment dindice 0 correspond au nom de la fonction en
cours dexcution. Le dernier lment correspond main.
Cette variable existe uniquement pendant lexcution
dune fonction shell.

Le comportement destin aux dbogueurs est activ :


loption -F de declare affiche le nom du fichier source et le
numro de ligne correspondant chaque nom de fonction
pass en argument, si la commande excute par le gestionnaire de DEBUG retourne une valeur diffrente de zro
alors la commande suivante est saute et non excute, et
si la commande excute par le gestionnaire de DEBUG
retourne la valeur 2 et si le shell se trouve dans une sousroutine alors un appel return est simul.

Description

524
Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

allexport

-a

Nom complet
de set

Option
de set

gnu_errfmt

Option de shopt

RT

HOME

BASH_VERSION
R

Le rpertoire personnel (daccueil).

Les messages derreurs du shell sont affichs en respectant


le format standard de GNU.

Marquer la fin des options. Tous les arguments restants


sont affects aux paramtres positionnels. -x et -v sont
dsactives. Sil ny a pas dautres arguments pour set, les
paramtres positionnels restent inchangs.

Les options passes lors de linvocation du shell.

Le numro de version de cette instance de bash.

Les informations de version de cette instance de bash. Chaque lment du tableau dtient une partie du numro de
version.

Largument de loption dinvocation -c.

BASH_EXECUTION_
STRING
BASH_VERSINFO

Le nom dun fichier dfinissant lenvironnement excuter lors de linvocation du shell.

BASH_ENV

Exporter toutes les variables dfinies ou modifies par la


suite.

Incrmente de 1 chaque fois quune nouvelle instance (et


non un sous-shell) de bash est invoque. Elle permet de
connatre le niveau dimbrication des shells bash.

SHLVL

Description
Cette variable est incrmente de 1 chaque cration dun
sous-shell ou dun environnement de sous-shell. La valeur
initiale est 0. Un sous-shell est une copie du shell parent et
partage son environnement.

Type var.
denv.

BASH_SUBSHELL

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

Ajuster le comportement du shell avec set, shopt et les variables


525

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

-k

--

Option
de set

keyword

Nom complet
de set

huponexit

Option de shopt

Utilise pour dterminer les paramtres rgionaux de


toute catgorie non spcifiquement choisie par une variable commenant par LC_.
Supplante la valeur de $LANG et de toute autre variable LC_
qui prcise une catgorie de paramtres rgionaux.
Dtermine lordre de rassemblement employ lors du tri
des rsultats dune expansion de noms de chemins.
Dtermine linterprtation des caractres et le comportement des classes de caractres dans lexpansion des noms
de chemins et la correspondance de motifs.

LC_ALL
LC_COLLATE
LC_CTYPE

Placer les arguments de keyword dans lenvironnement


dune commande.

Le sparateur de champs interne (Internal Field Separator) :


une liste des caractres qui servent de sparateurs de mots.
Elle contient par dfaut une espace, une tabulation et un
saut de ligne.

Sans autre argument, dsaffecter les paramtres positionnels. Sinon, les paramtres positionnels prennent la valeur
des arguments suivants (mme sils commencent par -).

LANG

IFS

Le type de machine sur laquelle sexcute bash.


bash envoie SIGHUP toutes les tches lors de la terminaison dun shell douverture de session interactif.

Le nom de lhte courant.

Description

HOSTTYPE

Type var.
denv.

HOSTNAME

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

526
Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

-B

Option
de set

braceexpand

Nom complet
de set

Les fonctions de correspondance de motifs tendue sont


actives.
Les motifs qui ne correspondent aucun nom de fichier
pendant lexpansion du nom de chemin gnrent une
erreur dexpansion.

extglob
failglob

La liste des motifs dfinissant les noms de fichiers ignorer lors de lexpansion des noms de chemins.

Les alias sont dvelopps.

expand_aliases

Les noms de fichiers qui commencent par un . sont pris


en compte lors de lexpansion du nom de chemin.

GLOBIGNORE

Le shell effectue lexpansion des crochets. Elle est active


par dfaut.

Le chemin de recherche des commandes.


Le nombre de secondes coules depuis linvocation du
shell.

SECONDS

Une chane qui dcrit le systme sur lequel bash sexcute.

PATH

MACHTYPE

Indique que bash a t dmarr comme un shell douverture de session. Cette valeur est en lecture seule.

Dtermine les paramtres rgionaux servant la mise en


forme des nombres.

LC_NUMERIC

Description
Dtermine les paramtres rgionaux servant la traduction des chanes entre guillemets prcdes dun symbole
$.

Type var.
denv.

LC_MESSAGES

Variable denvironnement

dotglob

login_shell

Option de shopt

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

Ajuster le comportement du shell avec set, shopt et les variables


527

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Nom complet
de set

noglob

hashall

Option
de set

[05/03/08]

-f

-h

HISTCONTROL

HISTCMD

Lhistorique est ajout au fichier indiqu par la valeur de


la variable $HISTFILE lorsque le shell se termine, au lieu
dcraser le fichier.

histappend

Une liste de motifs, spars par des deux-points (:), qui peuvent avoir les valeurs suivantes : ignorespace (les lignes
commenant par une espace ne sont pas ajoutes lhistorique), ignoredups (les lignes correspondant la dernire
ligne de lhistorique ne sont pas ajoutes), erasedups (toutes les lignes prcdentes correspondant la ligne actuelle
sont retires de lhistorique avant que celle-ci soit ajoute)
et ignoreboth (active ignorespace et ignoredups).

Le numro dhistorique de la commande en cours.

Prcise les caractres de contrle de lhistorique. Par


dfaut, il sagit de la chane !^#.

Tenter denregistrer toutes les lignes dune commande sur


plusieurs lignes dans une mme entre de lhistorique.

cmdhist

Activer le hachage des commandes.

Avant dexcuter les commandes qui se trouvent dans la


table de hachage, leur existence est vrifie et leur absence
conduit une recherche dans les rpertoires de $PATH.

Dsactiver lexpansion du nom de chemin.

La compilation des noms de chemins se fait de manire


insensible la casse.

Description

checkhash

Type var.
denv.

Les motifs qui ne correspondent aucun fichier sont remplacs par des chanes nulles et non par eux-mmes.

histchars

Variable denvironnement

nullglob

nocaseglob

Option de shopt

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

528
Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

histexpand

-H

history

Nom complet
de set

Option
de set

histverify

histreedit

Option de shopt

Une liste de motifs qui dterminent ce qui entre dans lhistorique.

HISTIGNORE

Lorsquelle est dfinie et non nulle, sa valeur est utilise


comme chane de format strftime(3) pour laffichage de
lestampille temporelle associe chaque rentre dhistorique prsente par la commande history. Si cette variable
est dfinie, les estampilles temporelles sont crites dans le
fichier dhistorique afin dtre conserves entre les sessions
du shell.

HISTTIMEFORMAT

Si readline est utilise, les rsultats de la substitution dhistorique ne sont pas immdiatement passs lanalyseur
du shell. la place, la ligne rsultante est charge dans le
tampon ddition de readline afin quelle puisse tre modifie si ncessaire.

Le nombre de lignes conserves dans lhistorique des commandes.

HISTSIZE

Si readline est utilise, il est possible de remodifier une


substitution dhistorique qui a chou.

Activer lhistorique des commandes. Elle est active par


dfaut dans les shells interactifs.

Le nombre maximum de lignes conserves dans le fichier


dhistorique.

HISTFILESIZE

Activer la substitution dhistorique avec !. Elle est active


par dfaut dans les shells interactifs.

Description

Le nom du fichier dhistorique des commandes.

Type var.
denv.

HISTFILE

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

Ajuster le comportement du shell avec set, shopt et les variables


529

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Option
de set

[05/03/08]

emacs

ignoreeof

Nom complet
de set

interactive_
comments

FCEDIT

DIRSTACK

RTU

Accepter les mots commenant par #, en ignorant tous les


caractres suivants de la ligne, dans un shell interactif.

Lditeur par dfaut de la commande fc.

Utiliser ldition de la ligne de commande de type Emacs.

Le contenu actuel de la pile de rpertoires.

Vrifier la taille de la fentre aprs chaque commande et,


si elle a chang, actualiser les variables $LINES et $COLUMNS
en consquence.

Une liste des rpertoires recherchs par la commande cd.

Lorsquun argument de cd nest pas un rpertoire, il est


considr comme un nom de variable qui contient le
rpertoire cible.

Interdire la sortie du shell par Ctrl-D.

Le nombre de caractres EOF reus avant de clore un shell


interactif.

Si loption cmdhist est active, les commandes sur plusieurs lignes sont enregistres dans lhistorique en remplaant les points-virgules par des sauts de ligne, lorsque cest
possible.

Description

checkwinsize

Type var.
denv.

Les petites erreurs dcriture du rpertoire fourni la commande cd seront corriges si une correspondance existe.
Cette correction concerne les lettres manquantes, les lettres incorrectes et les inversions de lettres. Elle fonctionne
uniquement dans les shells interactifs.

CDPATH

IGNOREEOF

Variable denvironnement

cdspell

cdable_vars

lithist

Option de shopt

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

530
Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

-m

Option
de set

monitor

vi

Nom complet
de set

shift_verbose

promptvars

Option de shopt

La chane de linvite de la commande select.


La chane de linvite de loption xtrace.

PS3
PS4

auto_resume

Activer le contrle des tches. Elle est active par dfaut


dans les shells interactifs.

Dtermine le fonctionnement du contrle des tches (les


valeurs sont exact, substring ou autre chose que ces
mots-cls).

Utiliser ldition de la ligne de commande de type vi.

Le dernier argument de la commande prcdente.

Fixe un entier positif, elle indique le nombre de secondes aprs lequel le shell se termine automatiquement en
labsence de saisie.

TMOUT

Prcise le format de sortie du mot rserv time dans un


tube de commandes.

TIMEFORMAT

La commande interne shift affiche une erreur lorsque le


dcalage dpasse le dernier paramtre positionnel.

Le rpertoire de travail.

La chane de linvite pour les continuations de ligne.

PS2

PWD

La chane de linvite principale.

PS1

Sa valeur est excute comme une commande avant laffichage de linvite principale.
Les chanes dinvite sont sujettes lexpansion des variables et des paramtres aprs avoir t dveloppes.

Le rpertoire de travail prcdent.

Description

PROMPT_COMMAND

Type var.
denv.

OLDPWD

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

Ajuster le comportement du shell avec set, shopt et les variables


531

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

notify

-b

posix

pipefail

Nom complet
de set

Option
de set

mailwarn

Option de shopt

PIPESTATUS

MAILPATH

Changer le comportement afin quil se conforme la


norme POSIX 1003.2 l o ce nest pas le cas par dfaut.

Une variable tableau contenant la liste des codes de sortie


des processus impliqus dans le dernier tube excut au
premier plan.

La valeur de retour dun tube est celle de la dernire commande qui se termine avec un code dtat diffrent de zro
ou bien zro si toutes les commandes du tube se terminent avec succs. Elle est dsactive par dfaut.

Si le fichier consult pour dterminer larrive de messages a t manipul depuis la dernire vrification, le message The mail in fichier_de_courrier has been read est
affich.

La liste des noms de fichiers consulter pour dterminer


larrive dun nouveau message lectronique, si $MAIL nest
pas dfinie.

Lintervalle (en secondes) de vrification de larrive dun


nouveau message lectronique.

MAILCHECK

Afficher immdiatement le code de sortie des tches


darrire-plan qui se terminent.

Description

Le nom du fichier consulter pour dterminer larrive


dun nouveau message lectronique.

Type var.
denv.

MAIL

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

532
Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Option
de set

Nom complet
de set

[05/03/08]

xpg_echo

Option de shopt

Chacun des paramtres positionnels passs au script ou


la fonction, donns sous forme dune liste de chanes entre
guillemets (par exemple, "arg1" "arg2" "arg3").

Le nom de chemin complet utilis pour invoquer cette


instance de bash.

Une chane contenant les paramtres positionnels passs


au script ou la fonction. Les paramtres sont spars par
le premier caractre de la variable $IFS (par exemple, arg1
arg2 arg3).

BASH

Le nom du shell ou du script.

echo dveloppe par dfaut les squences dchappement


base de barre oblique inverse.

Si cette variable existe dans lenvironnement au dmarrage de bash, linterprteur de commandes entre en mode
POSIX avant de lire les fichiers de dmarrage, comme si
loption --posix avait t fournie lors de linvocation. Si
elle est fixe pendant lexcution du shell, bash active le
mode POSIX, comme si la commande set -o posix avait
t invoque.

Description

Un tableau dont les lments sont affects avec loprateur


binaire =~ dans la commande conditionnelle [[. Llment
dindice 0 est la partie de la chane qui correspond
lexpression rgulire complte. Llment dindice n est la
partie de la chane qui correspond la nme sous-expression entre parenthses.

Type var.
denv.

RT

BASH_REMATCH

POSIXLY_CORRECT

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

Ajuster le comportement du shell avec set, shopt et les variables


533

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

nounset

errexit

-e

-u

Nom complet
de set

Option
de set

execfail

Option de shopt
Lidentifiant du processus du shell.

Le nombre darguments passs au script ou la fonction.


Lidentifiant du processus parent.

R
R

Le systme dexploitation sur lequel bash sexcute.

OSTYPE
PPID

Le numro du premier argument aprs les options.

OPTIND
#

Si elle vaut 1, les messages derreur de getopts sont affichs.

OPTERR

Considrer les variables non dfinies comme des erreurs et


non comme nulles.

Un tableau contenant la liste des groupes dont lutilisateur


courant est membre.

La valeur du dernier argument doption trait par


getopts.

RT

OPTARG

GROUPS

Lidentifiant du processus de la dernire commande en


arrire-plan.

Un shell non interactif ne se terminera pas sil ne peut pas


excuter largument dune commande exec. Les shells interactifs ne se terminent pas en cas dchec de exec.

Lidentifiant dutilisateur rel de lutilisateur connect.

EUID

Quitter le shell lorsquune commande simple se termine


avec un code de sortie diffrent de zro. Une commande
simple est une commande qui ne fait pas partie dune
construction while, until ou if, ni dune liste && ou ||, ni
une commande dont la valeur de retour est inverse par !.

Description

Type var.
denv.

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

534
Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Nom complet
de set

privileged

Option
de set

-p

Option de shopt

[05/03/08]

Lidentifiant de lutilisateur courant.

Le nom de chemin complet du shell.

SHELL
UID

La rponse de lutilisateur la commande select. Le rsultat de la commande read si aucun nom de variable na t
prcis.

Un nombre alatoire entre 0 et 32 767 (215 - 1).

RANDOM
REPLY

Le code de sortie de la commande prcdente.

Le script sexcute en mode privilgi (suid).

Description

Type var.
denv.

Variable denvironnement

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)

Ajuster le comportement du shell avec set, shopt et les variables


535

Elodie FRITSCH <elodie.fritsch@total.com>

536

Annexe A Listes de rfrence

Oprateurs de test
Les oprateurs du tableau A-9 semploient avec test et les constructions [...] et [[...]].
Vous pouvez les combiner logiquement avec -a ( et ) et -o ( ou ) et les regrouper
avec des parenthses chappes (\(...\)). Les comparaisons de chanes < et >, ainsi que
la construction [[...]] sont disponibles dans bash 2.0+. =~ nexiste que dans bash 3.0+.
Tableau A-9. Oprateurs de test
Oprateur

Vrai si

-a fichier

fichier existe, obsolte, identique -e.

-b fichier

fichier existe et est un priphrique en mode bloc.

-c fichier

fichier existe et est un priphrique en mode caractre.

-d fichier

fichier existe et est un rpertoire.

-e fichier

fichier existe, identique -a.

-f fichier

fichier existe et est un fichier normal.

-g fichier

fichier existe et son bit SGID (set group ID) est positionn.

-G fichier

fichier existe et appartient lidentifiant de groupe rel.

-h fichier

fichier existe et est un lien symbolique, identique -L.

-k fichier

fichier existe et son bit sticky est positionn.

-L fichier

fichier existe et est un lien symbolique, identique -h.

-n chane

chane nest pas nulle.

-N fichier

fichier a t modifi depuis sa dernire lecture.

-O fichier

fichier existe et appartient lidentifiant dutilisateur rel.

-p fichier

fichier existe et est un tube nomm ou non (fichier FIFO).

-r fichier

fichier existe et peut tre lu.

-s fichier

fichier existe et nest pas vide.

-S fichier

fichier existe et est une socket.

-t N

Le descripteur de fichier N pointe vers un terminal.

-u fichier

fichier existe et son bit SUID (set user ID) est positionn.

-w fichier

fichier existe et peut tre modifi.

-x fichier

fichier existe et peut tre excut, ou fichier est un rpertoire que lon peut parcourir.

-z chane

chane a une longueur gale zro.

fichierA -nt fichierB

La date de modification de fichierA est plus rcente que


celle de fichierB.

fichierA -ot fichierB

La date de modification de fichierA est plus ancienne que


celle de fichierB.

fichierA -ef fichierB

fichierA et fichierB dsigne le mme fichier.

chaneA = chaneB

chaneA est gale chaneB (version POSIX).

chaneA == chaneB

chaneA est gale chaneB.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Redirection des entres/sorties

537

Tableau A-9. Oprateurs de test (suite)


Oprateur

Vrai si

chaneA != chaneB

chaneA ne correspond pas chaneB.

chaneA =~ expreg

chaneA correspond lexpression rgulire tendue


regexpa.

chaneA < chaneB

chaneA se trouve avant chaneB dans lordre lexicographique.

chaneA > chaneB

chaneA se trouve aprs chaneB dans lordre lexicographique.

exprA -eq exprB

Les expressions arithmtiques exprA et exprB sont gales.

exprA -ne exprB

Les expressions arithmtiques exprA et exprB sont diffrentes.

exprA -lt exprB

exprA est infrieure exprB.

exprA -gt exprB

exprA est suprieure exprB.

exprA -le exprB

exprA est infrieure ou gale exprB.

exprA -ge exprB

exprA est suprieure ou gale exprB.

exprA -a exprB

exprA est vraie et exprB est vraie.

exprA -o exprB

exprA est vraie ou exprB est vraie.

a.

Uniquement disponible dans bash version 3.0 et ultrieures. Ne peut tre employ que
dans [[...]].

Redirection des entres/sorties


Le tableau A-10 prsente lintgralit des oprateurs de redirection des entres/sorties.
Notez quil existe deux formats pour indiquer la redirection de STDOUT et de
STDERR : &>fichier et >&fichier. Le second, employ tout au long de ce livre, est celui
recommand.
Tableau A-10. Redirection des entres/sorties
Redirecteur

Fonction

cmd1 | cmd2

Tube ; la sortie standard de cmd1 devient lentre standard de cmd2.

> fichier

La sortie standard est redirige vers fichier.

< fichier

Lentre standard est lue depuis fichier.

>> fichier

La sortie standard est redirige vers fichier ; si fichier existe dj, elle
lui est ajoute.

>| fichier

La sortie standard est redirige vers fichier mme si noclobber est


positionne.

n>| fichier

La sortie standard du descripteur de fichier n est redirige vers fichier


mme si noclobber est positionne.

<> fichier

fichier est utilis comme entre et sortie standard.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

538

Annexe A Listes de rfrence

Tableau A-10. Redirection des entres/sorties (suite)


Redirecteur

Fonction

n<> fichier

fichier est utilis comme entre et sortie standard pour le descripteur


de fichier n.

<< tiquette

Here document.

n> fichier

Le descripteur de fichier n est redirig vers fichier.

n< fichier

Le descripteur de fichier n est pris depuis fichier.

>> fichier

Le descripteur de fichier n est redirig vers fichier ; si fichier existe


dj, il lui est ajout.

n>&

La sortie standard est duplique vers le descripteur de fichier n.

n<&

Lentre standard est duplique depuis le descripteur de fichier n.

n>&m

Le descripteur de fichier n devient une copie du descripteur de fichier


de sortie m.

n<&m

Le descripteur de fichier n devient une copie du descripteur de fichier


dentre m.

&>fichier

La sortie et lerreur standard sont rediriges vers fichier.

<&-

Lentre standard est ferme.

>&-

La sortie standard est ferme.

n>&-

La sortie du descripteur de fichier n est ferme.

n<&-

Lentre du descripteur de fichier n est ferme.

n>&mot

Si n nest pas prcis, la sortie standard (descripteur de fichier 1) est utilise. Si le mot ne dsigne pas un descripteur de fichier ouvert en sortie, une erreur de redirection se produit. Cas particulier : si n est omis
et si mot ne contient pas un ou plusieurs chiffres, la sortie et lerreur
standard sont rediriges comme dcrit prcdemment.

n<&mot

Si mot contient un ou plusieurs chiffres, le descripteur de fichier indiqu par n devient une copie du descripteur de fichier reprsent par
mot. Si les chiffres de mot ne dsignent pas un descripteur des fichier
ouvert en entre, une erreur de redirection se produit. Si mot contient
-, le descripteur de fichier n est ferm. Si n nest pas indiqu, lentre
standard (descripteur de fichier 0) est utilise.

n>&chiffre-

Le descripteur de fichier chiffre devient le descripteur de fichier n, ou


bien la sortie standard (descripteur de fichier 1) si n est omis.

n<&chiffre-

Le descripteur de fichier chiffre devient le descripteur de fichier n, ou


bien lentre standard (descripteur de fichier 0) si n est omis. chiffre
est ferm aprs avoir t dupliqu vers n.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Options et squences dchappement de echo

539

Options et squences dchappement de echo


echo accepte les arguments donns au tableau A-11.
Tableau A-11. Options de echo
Options

Fonction

-e

Activer linterprtation des caractres chapps laide de la barre oblique


inverse.

-E

Dsactiver linterprtation des caractres chapps laide de la barre oblique inverse sur les systmes qui configurent ce mode par dfaut.

-n

Omettre le saut de ligne final (identique la squence dchappement \c).

echo accepte plusieurs squences dchappement qui commencent par une barre oblique inverse.
Les squences prsentes au tableau A-12 ont un comportement prvisible, except \f
qui, selon les terminaux, efface lcran ou provoque un saut de ligne et jecte la page sur
la plupart des imprimantes. \v est, en quelque sorte, obsolte ; elle gnre gnralement un saut de ligne.
Tableau A-12. Squences dchappement de echo
Squence

Caractre affich

\a

Alarme ou Ctrl-G (sonnerie).

\b

Espace arrire ou Ctrl-H.

\c

Supprimer le saut de ligne final.

\e

Caractre dchappement (identique \E).

\E

Caractre dchappement.

\f

Changement de page ou Ctrl-L.

\n

Saut de ligne (non la fin dune commande) ou Ctrl-J.

\r

Retour (Entre) ou Ctrl-M.

\t

Tabulation ou Ctrl-I.

\v

Tabulation verticale ou Ctrl-K.

\nnnn

Le caractre sur 8 bits dont la valeur octale (base 8) est donne par nnn
(sur 1 3 chiffres).

\0nnn

Le caractre sur 8 bits dont la valeur octale (base 8) est donne par nnn
(sur 0 3 chiffres).

\xHH

Le caractre sur 8 bits dont la valeur hexadcimale (base 16) est donne
par HH (sur 1 ou 2 chiffres).

\\

Barre oblique inverse.

Les squences \n, \0 et \x sont fortement dpendantes du priphrique et peuvent tre


employes pour des entres/sorties complexes, comme le contrle du curseur et les caractres graphiques spciaux.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

540

Annexe A Listes de rfrence

printf
La commande printf, disponible dans bash depuis sa version 2.02, est constitue de deux
parties (outre le nom de la commande) : une chane de format et un nombre variable
darguments :
printf chane-format [arguments]

chane-format contient les spcifications de format ; il sagit gnralement dune chane


constante place entre guillemets. arguments est une liste, comme une liste de chanes
ou de variables qui correspondent aux spcifications de format.
Le format est rutilis autant que ncessaire afin de traiter tous les arguments. Sil requiert plus darguments que ceux fournis, les spcifications de formats supplmentaires
se comportent comme si une valeur zro ou une chane nulle avait t indique.
Une spcification de format est compose dun symbole de pourcentage (%) et dun caractre parmi ceux donns au tableau A-13. Les deux formats principaux sont %s pour
les chanes et %d pour les entiers dcimaux.
Tableau A-13. Indicateurs de format pour printf
Caractre
de format

Signification

%c

Caractre ASCII (affiche le premier caractre de largument correspondant).

%d, %i

Entier dcimal (base 10).

%e

Format en virgule flottante ([-]d.prcisione[+-]dd) voir les explications


de prcision aprs ce tableau.

%E

Format en virgule flottante ([-]d.prcisionE[+-]dd).

%f

Format en virgule flottante ([-]ddd.prcision).

%g

Conversion %e ou %f, selon celle qui est la plus courte, avec suppression des
zros de fin.

%G

Conversion %E ou %f, selon celle qui est la plus courte, avec suppression des
zros de fin.

%o

Valeur octale non signe.

%s

Chane de caractres.

%u

Valeur dcimale non signe.

%x

Nombre hexadcimal non sign ; utilise a-f pour les valeurs 10 15.

%X

Nombre hexadcimal non sign ; utilise A-F pour les valeurs 10 15.

%%

Symbole %.

La commande printf permet de prciser la largeur et lalignement des champs affichs.


Une expression de format peut prendre trois modificateurs facultatifs aprs le symbole
% et avant le caractre de format :
%attributs largeur.prcision caractre-de-format

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

printf

541

La largeur du champ de sortie est une valeur numrique. Lorsquelle est prcise, le contenu du champ est, par dfaut, align droite. Vous devez ajouter lattribut - pour quil
soit align gauche (les autres attributs sont dcrits au tableau A-16). Ainsi, %-20s affiche une chane aligne gauche dans un champ dune largeur de 20 caractres. Si la longueur de la chane est infrieure 20 caractres, le champ est complt par des espaces.
Dans les exemples suivants, lindicateur de format est plac entre deux | dans la chane
de format afin que vous puissiez voir la largeur du champ. Le premier exemple aligne
droite le texte :
printf "|%10s|\n" bonjour

Il produit laffichage suivant :


|

bonjour|

Le deuxime exemple aligne le texte gauche :


printf "|%-10s|\n" bonjour

On obtient ainsi :
|bonjour

Le modificateur de prcision, employ avec les valeurs dcimales ou en virgule f lottante, dtermine le nombre de chiffres qui apparaissent dans le rsultat. Pour les chanes
de caractres, il fixe le nombre maximum de caractres affichs.
Vous pouvez indiquer la largeur et la prcision de manire dynamique, via des valeurs
de la liste des arguments de printf. Pour cela, remplacez les valeurs littrales par des astrisques dans lexpression de format :
$ mavar=42.123456
$ maprec=6
$ printf "|%*.*G|\n" 5 $maprec $mavar
|42.1235|

Dans cet exemple, la largeur est 5, la prcision vaut 6 et la valeur affiche se trouve dans
$mavar. La prcision est facultative et sa signification relle varie en fonction de la lettre
qui vient aprs (voir le tableau A-14).
Tableau A-14. Signification de prcision selon lindicateur de format de printf
Format

Signification de prcision

%d, %I, %o, %u, %x, %X

Le nombre minimum de chiffres affichs. Lorsque la valeur


contient un nombre de chiffres infrieur elle est complte par
des zros placs au dbut. La prcision par dfaut est 1.

%e, %E

Le nombre minimum de chiffres affichs. Lorsque la valeur


contient un nombre de chiffres infrieur, elle est complte par
des zros placs aprs la virgule. La prcision par dfaut est 10.
La prcision 0 dsactive laffichage de la virgule.

%f

Le nombre de chiffres droite de la virgule.

%g, %G

Le nombre maximum de chiffres significatifs.

%s

Le nombre maximum de caractres affichs.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

542

Annexe A Listes de rfrence

Tableau A-14. Signification de prcision selon lindicateur de format de printf (suite)


Format

Signification de prcision

%b

(Shell POSIX peut tre non portable sur les autres versions
de printf.) Utilise avec %s, elle permet de dvelopper les squences dchappement de type echo contenues dans la chane en
argument (voir le tableau A-15).

%q

(Shell POSIX peut tre non portable sur les autres versions
de printf.) Utilise avec %s, elle affiche la chane en argument de
manire ce quelle puisse servir dentre pour le shell.

%b et %q sont des ajouts bash (et aux autres shells compatibles POSIX) qui apportent
des fonctionnalits utiles, mais qui remettent en cause la portabilit avec les versions de
la commande printf disponibles dans dautres shells et dautres parties dUnix. Voici des
exemples qui vous permettront de comprendre leur fonctionnement :
%q pour obtenir une chane compatible avec le shell :
$ printf "%q\n" "bonjour vous tous"
bonjour\ \ vous\ tous

%b pour interprter les chappements de type echo :


$ printf "%s\n" 'bonjour\ncher ami'
bonjour\ncher ami
$ printf "%b\n" 'bonjour\ncher ami'
bonjour
cher ami

Le tableau A-15 prsente les squences dchappement qui seront converties lorsque que
la chane est affiche avec le format %b.
Tableau A-15. Squences dchappement de printf
Squence
dchappement

Signification

\e

Caractre dchappement.

\a

Caractre dalarme.

\b

Caractre despace arrire.

\f

Caractre de changement de page.

\n

Caractre de saut de ligne.

\r

Caractre de retour chariot.

\t

Caractre de tabulation.

\v

Caractre de tabulation verticale.

\'

Caractre de lapostrophe.

\"

Caractre des guillemets.

\\

Caractre de la barre oblique inverse.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

printf

543

Tableau A-15. Squences dchappement de printf (suite)


Squence
dchappement

Signification

\nnn

Le caractre sur 8 bits dont la valeur ASCII est donne par le chiffre
octal nnn (sur 1 3 chiffres).

\xHH

Le caractre sur 8 bits dont la valeur ASCII est donne par le chiffre
hexadcimal HH (sur 1 ou 2 chiffres).

Enfin, vous pouvez indiquer un ou plusieurs attributs avant la largeur de champ et la


prcision. Nous avons dj mentionn lattribut - pour lalignement gauche. Lensemble complet des attributs est donn au tableau A-16.
Tableau A-16. Attributs de printf
Caractre

Description

Aligner gauche dans le champ la valeur mise en forme.

espace

Prfixer les valeurs positives par une espace et la valeur ngative par un
signe moins.

Toujours prfixer les valeurs numriques par un signe, mme lorsquelles


sont positives.

Utiliser une forme alternative : %o est prcd de 0 ; %x et %X sont prcds


de 0x et 0X, respectivement ; %e, %E et %f affichent toujours une virgule ; %g
et %G ne suppriment pas les zros de fin.

Complter le champ par des zros, non des espaces. Cela ne se produit que
lorsque la largeur du champ est suprieure celle de largument converti.
Dans le langage C, cet attribut sapplique tous les formats de sortie,
mme ceux qui ne sont pas numriques. Dans bash, il ne sapplique quaux
formats numriques.

'

Mettre en forme avec les caractres de sparation des milliers, pour les formats %i, %d, %u, %f, %F, %g et %G (bien que dfini par POSIX, il nest pas
encore implment).

Exemples
Les exemples de printf donns au tableau A-17 utilisent une variable du shell :
PI=3.141592653589

Tableau A-17. Exemples de printf


Instruction printf

Rsultat

Commentaires

printf '%f\n' $PI

3.141593

Notez larrondi par dfaut.

# Non voulu
printf '%f.5\n' $PI

3.14.5

Une erreur classique. Lindicateur de format doit se trouver de lautre ct de %f.


Puisque ce nest pas le cas, les caractres .5
sont ajouts comme nimporte quel texte.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

544

Annexe A Listes de rfrence

Tableau A-17. Exemples de printf (suite)


Instruction printf

Rsultat

Commentaires

printf '%.5f\n' $PI

3.14159

Accorde cinq chiffres droite de la virgule.

printf '%+.2f\n' $PI

+3.14

Signe + de dbut, uniquement deux chiffres aprs la virgule.

printf '[%.4s]\n' s chaine

[s]
[chai]

Tronque quatre caractres. Avec un seul


caractre, la sortie ne contient que lui. La
chane de format est rutilise.

printf '[%4s]\n' s chaine

[ s]
[chaine]

Garantit un champ dau moins quatre


caractres, aligns droite. Le contenu
nest pas tronqu.

printf '[%-4.4s]\n' s chaine [s ]


[chai]

Combine le tout. Une largeur minimum


de quatre caractres, une largeur maximum de quatre caractres, avec coupure si
ncessaire, et alignement gauche ( cause
du signe moins) si la longueur est infrieure quatre caractres.

Voici un autre exemple qui ne tient pas dans le tableau prcdent. En gnral, les instructions printf sont crites en plaant toute la mise forme, y compris les sauts de ligne,
dans la chane de format. Cest le cas de celles du tableau A-17. Nous vous conseillons de
procder ainsi, mais rien ne vous y oblige et il est mme parfois plus facile de faire autrement. Le symbole reprsente une tabulation :
$ printf "%b" "\aActiver lalarme, puis tabulation\t puis saut de
ligne\nPuis ligne 2.\n"
Activer lalarme, puis tabulationpuis saut de ligne
Puis ligne 2.

Voir aussi

http://www.opengroup.org/onlinepubs/009695399/functions/printf.html.

Mettre en forme la date et lheure avec strftime


Le tableau A-18 prsente les options les plus courantes pour la mise en forme des chanes
de date et dheure. Consultez les pages de manuel de date et de strftime(3) sur votre systme, car les options et leur signification varient frquemment.
Tableau A-18. Code de format de strftime
Format

Description

%%

Un symbole % littral.

%a

Le nom abrg du jour de la semaine conformment aux paramtres rgionaux (lun..dim).

%A

Le nom complet du jour de la semaine conformment aux paramtres


rgionaux (lundi..dimanche).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Mettre en forme la date et lheure avec strftime

545

Tableau A-18. Code de format de strftime (suite)


Format

Description

%B

Le nom complet du mois conformment aux paramtres rgionaux (janvier..dcembre).

%b ou %h

Le nom abrg du mois conformment aux paramtres rgionaux


(jan..dc).

%c

La reprsentation par dfaut/prfre de la date et de lheure conformment aux paramtres rgionaux.

%C

Le sicle (une anne divise par 100 et convertie en un entier) sous forme
de nombre dcimal (00..99).

%d

Le jour du mois sous forme de nombre dcimal (01..31).

%D

La date au format %m/%d/%y (MM/JJ/AA). Notez que les tats-Unis utilisent


MM/JJ/AA alors que les autres pays ont choisi JJ/MM/AA. Ce format est
donc ambigu et doit tre vit. la place, utilisez %F, puisquil est normalis et permet les tris.

%e

Le jour du mois sous forme dun nombre dcimal complt par une espace
( 1..31).

%F

La date au format %Y-%m-%d (date au format ISO 8601 : CCAA-MM-JJ) ;


except lorsque le nom du mois est affich en entier, comme sous HP-UX.

%g

Lanne sur deux chiffres correspondant au numro de la semaine %V


(AA).

%G

Lanne sur quatre chiffres correspondant au numro de la semaine %V


(CCAA).

%H

Lheure (sur 24 heures) sous forme de nombre dcimal (00..23).

%h ou %b

Le nom abrg du mois conformment aux paramtres rgionaux


(jan..dc).

%I

Lheure (sur 12 heures) sous forme de nombre dcimal (01..12).

%j

Le jour de lanne sous forme de nombre dcimal (001..366).

%k

Lheure (sur 24 heures) sous forme de nombre dcimal complt par une
espace ( 0..23).

%l

Lheure (sur 12 heures) sous forme de nombre dcimal complt par une
espace ( 1..12).

%m

Le mois sous forme de nombre dcimal (01..12).

%M

Les minutes sous forme de nombre dcimal (00..59).

%n

Un saut de ligne littral.

%N

Les nanosecondes (000000000..999999999). [GNU]

%p

Lindicateur rgional de AM ou PM .

%P

Lindicateur rgional de am ou pm . [GNU]

%r

Lheure (sur 12 heures) avec la notation AM/PM (HH:MM:SS AM/PM)


conformment aux paramtres rgionaux.

%R

Lheure au format %H:%M (HH:MM).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

546

Annexe A Listes de rfrence

Tableau A-18. Code de format de strftime (suite)


Format

Description

%s

Le nombre de secondes coules depuis lorigine (le 1er janvier 1970


00:00:00 UTC).

%S

Les secondes sous forme de nombre dcimal (00..61). Lintervalle est (0061) et non (00-59) afin dautoriser les secondes intercalaires.

%t

Une tabulation littrale.

%T

Lheure au format %H:%M:%S (HH:MM:SS).

%u

Le jour de la semaine (le lundi tant le premier jour) sous forme de nombre dcimal (1..7).

%U

Le numro de la semaine dans lanne (le dimanche tant le premier jour


de la semaine) sous forme de nombre dcimal (00..53).

%v

La date au format %e-%b-%Y (D-MMM-CCAA). [Non standard]

%V

Le numro de la semaine de lanne (le dimanche tant le premier jour de


la semaine) sous forme de nombre dcimal (01..53). Conformment la
norme ISO 8601, la semaine contenant le 1er janvier reprsente la semaine
1 si elle contient quatre jours ou plus de la nouvelle anne, sinon il sagit
de la semaine 53 de lanne prcdente et la semaine suivante constitue la
semaine 1. Lanne est donne par la conversion %G.

%w

Le jour de la semaine (le dimanche tant le premier jour) sous forme de


nombre dcimal (0..6).

%W

Le numro de la semaine de lanne (le lundi tant le premier jour de la


semaine) sous forme de nombre dcimal (00..53).

%x

La reprsentation de la date conformment aux paramtres rgionaux.

%X

La reprsentation de lheure conformment aux paramtres rgionaux.

%y

Lanne sans le sicle sous forme de nombre dcimal (00..99).

%Y

Lanne avec le sicle sous forme de nombre dcimal.

%z

Le fuseau horaire, comme un dcalage par rapport lUTC au format ISO


8601 [-]hhmm.

%Z

Le nom du fuseau horaire.

Caractres pour la correspondance de motifs


Le contenu de cette section est une version adapte du manuel de rfrence de bash
(http://www.gnu.org/software/bash/manual/bashref.html ; voir le tableau A-19).
Tableau A-19. Caractres pour la correspondance de motifs
Caractre

Signification

Correspondance avec nimporte quelle chane, y compris la


chane vide.

Correspondance avec nimporte quel caractre unique.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Oprateurs pour la correspondance de motifs tendue extglob

547

Tableau A-19. Caractres pour la correspondance de motifs (suite)


Caractre

Signification

[ ... ]

Correspondance avec lun des caractres placs entre les crochets.

[! ... ] ou [^ ... ]

Correspondance avec nimporte quel caractre autre que ceux


placs entre les crochets.

Les classes de caractres POSIX suivantes peuvent tre utilises avec [ ], par exemple
[[:alnum:]]. Consultez la page de manuel de grep ou de egrep sur votre systme.

[[:alnum:]]
[[:digit:]]
[[:space:]]
[[:word:]]

[[:alpha:]] [[:ascii:]]
[[:graph:]] [[:lower:]]
[[:upper:]]
[[:xdigit:]]

[[:blank:]]
[[:print:]]

[[:cntrl:]]
[[:punct:]]

La classe de caractres word correspond aux lettres, aux chiffres et au caractre _.


[=c=] correspond tous les caractres ayant le mme poids de collation (comme dfini
par les paramtres rgionaux) que le caractre c, tandis que [.symbole.] correspond au
symbole de collation symbole.
Ces classes de caractres tiennent compte des paramtres rgionaux. Pour obtenir les valeurs Unix classiques, utilisez LC_COLLATE=C ou LC_ALL=C.

Oprateurs pour la correspondance de motifs


tendue extglob
Les oprateurs dcrits au tableau A-20 sappliquent lorsque shopt -s extglob a t invoque. Les correspondances sont sensibles la casse, mais vous pouvez employer shopt
-s nocasematch (bash 3.1+) pour modifier ce comportement. Cette option affecte galement les commandes case et [[.
Tableau A-20. Oprateurs pour la correspondance de motifs tendue extglob
Regroupement

Signification

@( ... )

Uniquement une occurrence.

*( ... )

Zro ou plusieurs occurrences.

+( ... )

Une ou plusieurs occurrences.

?( ... )

Zro ou une occurrence.

!( ... )

Toute autre chose que cette occurrence.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

548

Annexe A Listes de rfrence

Squences dchappement de tr
Tableau A-21. Squences dchappement de tr
Squence

Signification

\ooo

Le caractre ayant la valeur octale ooo (sur 1 3 chiffres).

\\

Le caractre barre oblique inverse (autrement dit, chappement de


la barre oblique inverse elle-mme).

\a

Une sonnerie audio , le caractre ASCII BEL (puisque b est


pris pour lespace arrire).

\b

Lespace arrire.

\f

Le changement de page.

\n

Le saut de ligne.

\r

Le retour chariot.

\t

La tabulation (parfois appele tabulation horizontale).

\v

La tabulation verticale.

Syntaxe du fichier dinitiation de readline


La bibliothque Readline de GNU fournit la ligne de commande grce laquelle vous
communiquez avec bash et dautres utilitaires GNU. Ses possibilits de configuration
sont vastes, mais peu dutilisateurs en ont conscience.
Les tableaux A-22, A-23 et A-24 ne prsentent quun sous-ensemble des lments disponibles. Pour plus de dtails, consultez la documentation de Readline.
Ce contenu est directement adapt de la documentation de Chet Ramey (http://tiswww.
tis.case.edu/~chet/readline/readline.html).
Vous pouvez modifier le comportement lexcution de Readline en modifiant ses variables avec la commande set dans le fichier dinitialisation. La syntaxe est simple :
set variable valeur

Par exemple, voici comment passer du mode ddition de type Emacs par dfaut aux
commandes de type vi :
set editing-mode vi

Les noms des variables et les valeurs ne sont pas sensibles la casse. Les noms de variables non reconnus sont ignors.
Les variables boolennes (celles qui peuvent tre actives ou inactives) sont activs lorsque leur valeur est nulle ou vide, on (insensible la casse) ou 1. Toute autre valeur
inactive le comportement associ la variable.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Syntaxe du fichier dinitiation de readline

549

Tableau A-22. Paramtres de configuration de Readline


Variable

Description

bell-style

Dtermine ce qui se produit lorsque Readline doit faire


retentir la sonnerie du terminal. Si cette variable vaut none,
Readline ne gnre aucun bip. Avec la valeur visible, Readline emploie une sonnerie visible, si elle est disponible. Pour
audible (la valeur par dfaut), Readline tente de faire sonner
lalarme du terminal.

bind-tty-special-chars

Pour la valeur on, Readline tente de lier les caractres de contrle traits de manire spciale par le pilote de terminal du
noyau leurs quivalents Readline.

comment-begin

La chane insrer au dbut de la ligne lorsque la commande insert-comment est excute. Par dfaut, il sagit dun
caractre #.

completion-ignore-case

Pour la valeur on, Readline effectue la correspondance et la


compltion des noms de fichiers sans tenir compte de la
casse. La valeur par dfaut est off.

completion-query-items

Le nombre de compltions qui dtermine quand lutilisateur


doit confirmer laffichage de la liste des possibilits. Si le
nombre de compltions possibles est suprieur cette valeur,
Readline demande lutilisateur sil souhaite les voir. Sinon,
elles sont affiches. Cette variable doit tre fixe une valeur
entire suprieure ou gale 0. Une valeur ngative signifie
que Readline ne demande jamais la confirmation. La limite
par dfaut est 100.

convert-meta

Si elle vaut on, Readline convertit en une squence de touches ASCII les caractres dont le huitime bit est positionn,
en retirant le huitime bit et en ajoutant un caractre
dchappement. La valeur par dfaut est on.

disable-completion

Fixe on, Readline dsactive la compltion des mots. Les


caractres de compltion seront insrs dans la ligne comme
sils avaient t associs self-insert. La valeur par dfaut
est off.

editing-mode

Dtermine les liaisons de touche utilises. Par dfaut, Readline dmarre en mode ddition Emacs, avec des squences
de touche trs similaire celle dEmacs. Cette variable
accepte la valeur emacs ou vi.

enable-keypad

Pour la valeur on, Readline tente dactiver le pav numrique du clavier. Certains systmes en ont besoin pour disposer des touches de direction. La valeur par dfaut est off.

expand-tilde

Si elle vaut on, le dveloppement du tilde (~) est effectu lorsque Readline tente la compltion de mot. La valeur par
dfaut est off.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

550

Annexe A Listes de rfrence

Tableau A-22. Paramtres de configuration de Readline (suite)


Variable

Description

history-preserve-point

Lorsque sa valeur est on, le code de gestion de lhistorique


tente de placer le point (la position courante du curseur) au
mme emplacement sur chaque ligne dhistorique retrouve
avec previous-history ou next-history. La valeur par
dfaut est off.

horizontal-scroll-mode

Si cette variable vaut on, les lignes dites dfilent horizontalement lorsque la saisie dpasse le bord droit de lcran, au
lieu de passer sur une nouvelle ligne de lcran. La valeur par
dfaut est off.

input-meta

Pour la valeur on, Readline active les entres sur 8 bits (le
huitime bit des caractres lus nest pas effac), que le terminal indique quil prend en charge ce mode ou non. La valeur
par dfaut est off. meta-flag est un synonyme de cette variable.

isearch-terminators

La chane de caractres qui doit terminer une recherche


incrmentale sans que le caractre soit ensuite considr
comme une commande. Si cette variable nest pas dfinie, les
caractres chap et C-J terminent une recherche incrmentale.

keymap

Met en place le jeu de touches courant de Readline pour la


liaison des commandes. Les noms accepts sont emacs,
emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, vicommand et vi-insert. vi est quivalent vi-command ; emacs
est quivalent emacs-standard. La valeur par dfaut est
emacs. La valeur de la variable editing-mode affecte galement le jeu de touches par dfaut.

mark-directories

Si elle vaut on, une barre oblique est ajoute aux noms de
rpertoires complts. La valeur par dfaut est on.

mark-modified-lines

Pour la valeur on, Readline affiche une astrisque (*) au


dbut des lignes de lhistorique qui ont t modifies. La
valeur par dfaut est off.

mark-symlinkeddirectories

Fixe on, une barre oblique est ajoute aux noms complts qui correspondent des liens symboliques vers des rpertoires (voir aussi mark-directories). La valeur par dfaut est
off.

match-hidden-files

Pour la valeur on, Readline trouve une correspondance avec


les noms de fichiers commenant par un . (fichiers cachs),
lors de la compltion des noms de fichiers, except lorsque
le . initial est indiqu par lutilisateur. La valeur par dfaut
est on.

output-meta

Si elle vaut on, Readline affiche directement les caractres


dont le huitime bit est positionn et non comme des
squences dchappement. La valeur par dfaut est off.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Commande du mode Emacs

551

Tableau A-22. Paramtres de configuration de Readline (suite)


Variable

Description

page-completions

Fixe on, Readline utilise un mcanisme interne de pagination similaire more pour afficher les compltions possibles
un cran la fois. La valeur par dfaut est on.

print-completionshorizontally

Lorsque cette variable vaut on, Readline affiche les compltions tries horizontalement par ordre alphabtique et non
plus verticalement. La valeur par dfaut est off.

show-all-if-ambiguous

Modifie le fonctionnement par dfaut des fonctions de compltion. Pour la valeur on, les mots ayant plusieurs compltions possibles voient les correspondances affiches
immdiatement sans activer la sonnerie. La valeur par dfaut
est off.

show-all-if-unmodified

Modifie le fonctionnement par dfaut des fonctions de compltion de manire similaire show-all-if-ambiguous.
Lorsquelle vaut on, les mots ayant plusieurs compltions
possibles sans partager de compltion partielle (les compltions possibles nont pas de prfixe en commun) voient les
correspondances affiches immdiatement sans activer la
sonnerie. La valeur par dfaut est off.

visible-stats

Si elle vaut on, un caractre reprsentant le type de fichier est


ajout au nom de fichier lors de laffichage des compltions
possibles. La valeur par dfaut est off.

Commande du mode Emacs


Le contenu de cette section apparat galement dans le livre Le shell bash, 3e dition de
Cameron Newham et Bill Rosenblatt (ditions OReilly).
Le tableau A-23 est une liste complte des commandes ddition de Readline en mode
Emacs.
Tableau A-23. Commandes du mode Emacs
Commande

Signification

Ctrl-A

Dplacement en dbut de ligne.

Ctrl-B

Dplacement dun caractre vers larrire.

Ctrl-D

Suppression dun caractre vers lavant.

Ctrl-E

Dplacement en fin de ligne.

Ctrl-F

Dplacement dun caractre vers lavant.

Ctrl-G

Annule la commande ddition en cours et met un bip.

Ctrl-J

Identique Entre.

Ctrl-K

Suppresion vers lavant jusqu la fin de la ligne.

Ctrl-L

Effacement de lcran, puis raffichage de la ligne.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

552

Annexe A Listes de rfrence

Tableau A-23. Commandes du mode Emacs (suite)


Commande
Ctrl-M

Identique Entre.

Ctrl-N

Ligne suivant de lhistorique des commandes.

Ctrl-O

Identique Entre, puis affichage de la ligne suivante de lhistorique.

Ctrl-P

Ligne prcdente de lhistorique des commandes.

Ctrl-R

Recherche vers larrire.

Ctrl-S

Recherche vers lavant.

Ctrl-T

Interversion de deux caractres.

Ctrl-U

Suppresion de la ligne vers larrire partir du dbut jusquau point.

Ctrl-V

Entre tel quel du prochain caractre suivant.

Ctrl-V Tab

Insertion dune tabulation.

Ctrl-W

Suppresion du mot avant le curseur, lespace servant de dlimiteur.

Ctrl-X /

Liste des compltions de noms de fichiers pour le mot courant.

Ctrl-X ~

Liste des compltions de noms dutilisateurs pour le mot courant.

Ctrl-X $

Liste des compltions de variables shell pour le mot courant.

Ctrl-X @

Liste des compltions de noms dhtes pour le mot courant.

Ctrl-X !

Liste des compltions de noms de commandes pour le mot courant.

Ctrl-X (

Dbut de lenregistrement des caractres dans la macro clavier en


cours.

Ctrl-X )

Fin de lenregistrement des caractres dans la macro clavier en cours.

Ctrl-X e

Nouvelle excution de la dernire macro clavier dfinie.

Ctrl-X Ctrl-R

Lecture du contenu du fichier dinitialisation de readline.

Ctrl-X Ctrl-V

Affichage des informations de version de cette instance de bash.

Ctrl-Y

Rcupration (yank) du dernier lment dtruit.

Suppr

Effacement vers larrire dun caractre.

Ctrl-[

Identique chap (la plupart des claviers).

chap-B

Dplacement dun mot vers larrire.

chap-C

Conversion du mot aprs le point en lettres capitales.

chap-D

Suppression dun mot vers lavant.

chap-F

Dplacement dun mot vers lavant.

chap-L

Conversion du mot aprs le point en lettres minuscules.

chap-N

Recherche vers lavant non progressive.

chap-P

Recherche vers larrire non progressive.

chap-R

Annulation de toutes les modifications apportes cette ligne.

chap-T

Interversion de deux mots.

chap-U

Conversion du mot aprs le point en lettres majuscules.

chap-Ctrl-E

Expansion des alias, de lhistorique et des mots sur la ligne.

chap-Ctrl-H

Suppression dun mot vers larrire.

[05/03/08]

bash Le livre de recettes

Signification

Elodie FRITSCH <elodie.fritsch@total.com>

Commandes du mode vi

553

Tableau A-23. Commandes du mode Emacs (suite)


Commande

Signification

chap-Ctrl-Y

Insertion du premier argument de la commande prcdente (gnralement le deuxime mot) au point courant.

chap-Suppr

Suppression dun mot vers larrire.

chap-^

Expansion de lhistorique sur la ligne.

chap-<

Dplacement sur la premire ligne du fichier dhistorique.

chap->

Dplacement sur la dernire ligne du fichier dhistorique.

chap-.

Insertion du dernier mot de la commande de la ligne prcdente aprs


le point.

chap-_

Identique la prcdente.

Tab

Compltion de noms de fichiers sur le mot courant.

chap-?

Liste des compltions possibles pour le texte avant le point.

chap-/

Tentative de compltion de noms de fichiers sur le mot courant.

chap-~

Tentative de compltion de noms dutilisateurs sur le mot courant.

chap-$

Tentative de compltion de variables sur le mot courant.

chap-@

Tentative de compltion de noms dhtes sur le mot courant.

chap-!

Tentative de compltion de noms de commandes sur le mot courant.

chap-Tab

Tentative de compltion partir de lhistorique des commandes.

chap-~

Tentative de dveloppement du tilde sur le mot courant.

chap-\

Suppression de toutes les espaces et des tabulations autour du point.

chap-*

Insertion avant le point de toutes les compltions qui seraient gnres


par chap-=.

chap-=

Liste des compltions possibles avant le point.

chap-{

Tentative de compltion de noms de fichiers et renvoi de la liste au


shell entoure par des accolades.

Commandes du mode vi
Le contenu de cette section apparat galement dans le livre Le shell bash, 3e dition de
Cameron Newham et Bill Rosenblatt (ditions OReilly).
Le tableau A-24 est une liste complte des commandes ddition de Readline en mode vi.
Tableau A-24. Commandes du mode vi
Commande

Signification

Dplacement dun caractre vers la gauche.

Dplacement dun caractre vers la droite.

Dplacement dun mot vers la droite.

Dplacement dun mot vers la gauche.

Dplacement au dbut du mot non blanc suivant.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

554

Annexe A Listes de rfrence

Tableau A-24. Commandes du mode vi (suite)


Commande

Signification

Dplacement au dbut du mot non blanc prcdent.

Dplacement la fin du mot courant.

Dplacement la fin du mot non blanc courant.

Dplacement au dbut de la ligne.

Rptition de la dernire insertion a.

Dplacement sur le premier caractre non blanc de la ligne.

Dplacement la fin de la ligne.

Insertion du texte avant le caractre courant.

Insertion du texte aprs le caractre courant.

Insertion du texte au dbut de la ligne.

Insertion du texte la fin de la ligne.

Remplacement du texte existant.

dh

Suppression dun caractre vers larrire.

dl

Suppression dun caractre vers lavant.

db

Suppression dun mot vers larrire.

dw

Suppression dun mot vers lavant.

dB

Suppression dun mot non blanc vers larrire.

dW

Suppression dun mot non blanc vers lavant.

d$

Suppression jusqu la fin de la ligne.

d0

Suppression jusquau dbut de la ligne.

quivalent d$ (suppression jusqu la fin de la ligne).

dd

quivalent 0d$ (suppression de la ligne entire).

quivalent c$ (suppression jusqu la fin de la ligne, passage en mode


saisie).

cc

quivalent 0c$ (suppression de la ligne entire, passage en mode saisie).

quivalent dl (suppression dun caractre vers lavant).

quivalent dh (suppression dun caractre vers larrire).

k ou -

Dplacement dune ligne vers larrire.

j ou +

Dplacement dune ligne vers lavant.

Dplacement vers la ligne indique par le compteur de rptition.

/chane

Recherche de chane vers lavant.

?chane

Recherche de chane vers larrire.

Rptition de la recherche vers lavant.

Rptition de la recherche larrire.

fx

Dplacement vers la droite sur loccurrence suivante de x.

Fx

Dplacement vers la gauche sur loccurrence prcdente de x.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Tableau des valeurs ASCII

555

Tableau A-24. Commandes du mode vi (suite)


Commande

Signification

tx

Dplacement vers la droite sur loccurrence suivante de x, puis dplacement dune espace vers larrire.

Tx

Dplacement vers la gauche sur loccurrence prcdente de x, puis


dplacement dune espace vers lavant.

Rptition de la dernire commande de recherche de caractre.

Rptition de la dernire commande de recherche de caractre dans le


sens oppos.

Compltion de noms de fichiers.

Expansion des caractres gnriques (sur la ligne de commande).

\=

Expansion des caractres gnriques (dans une liste affiche).

Inversion de la casse de la slection courante.

Ajout du dernier mot de la commande prcdente, passage en mode


saisie.

Ctrl-L

Dmarrage dune nouvelle ligne et raffichage de la ligne en cours.

Ajout de # (caractre de commentaire) au dbut de la ligne, envoye


ensuite dans lhistorique.

Tableau des valeurs ASCII


La plupart de nos livres dinformatique prfrs fournissent un tableau des valeurs
ASCII. Mme lpoque des interfaces graphiques et des serveurs web, vous devez parfois retrouver un caractre. Cest souvent le cas avec la commande tr ou pour certaines
squences dchappement particulires.
Entier

Octal

Hexa.

ASCII

Entier

Octal

Hexa.

ASCII

000

00

^@

14

016

0e

^N

001

01

^A

15

017

0f

^O

002

02

^B

16

020

10

^P

003

03

^C

17

021

11

^Q

004

04

^D

18

022

12

^R

005

05

^E

19

023

13

^S

006

06

^F

20

024

14

^T

007

07

^G

21

025

15

^U

010

08

^H

22

026

16

^V

011

09

^I

23

027

17

^W

10

012

0a

^J

24

030

18

^X

11

013

0b

^K

25

031

19

^Y

12

014

0c

^L

26

032

1a

^Z

13

015

0d

^M

27

033

1b

^[

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

556
Entier

Octal

Hexa.

ASCII

Entier

Octal

Hexa.

ASCII

28

034

1c

^\

66

102

42

29

035

1d

^]

67

103

43

30

036

1e

^^

68

104

44

31

037

1f

^_

69

105

45

32

040

20

70

106

46

33

041

21

71

107

47

34

042

22

72

110

48

35

043

23

73

111

49

36

044

24

74

112

4a

37

045

25

75

113

4b

38

046

26

&

76

114

4c

39

047

27

77

115

4d

40

050

28

78

116

4e

41

051

29

79

117

4f

42

052

2a

80

120

50

43

053

2b

81

121

51

44

054

2c

82

122

52

45

055

2d

83

123

53

46

056

2e

84

124

54

47

057

2f

85

125

55

48

060

30

86

126

56

49

061

31

87

127

57

50

062

32

88

130

58

51

063

33

89

131

59

52

064

34

90

132

5a

53

065

35

91

133

5b

54

066

36

92

134

5c

55

067

37

93

135

5d

56

070

38

94

136

5e

57

071

39

95

137

5f

58

072

3a

96

140

60

59

073

3b

97

141

61

60

074

3c

<

98

142

62

61

075

3d

99

143

63

62

076

3e

>

100

144

64

63

077

3f

101

145

65

64

100

40

102

146

66

65

101

41

103

147

67

[05/03/08]

bash Le livre de recettes

Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

Tableau des valeurs ASCII


Entier

Octal

Hexa.

ASCII

Entier

Octal

Hexa.

ASCII

104

150

68

116

164

74

105

151

69

117

165

75

106

152

6a

118

166

76

107

153

6b

119

167

77

108

154

6c

120

170

78

109

155

6d

121

171

79

110

156

6e

122

172

7a

111

157

6f

123

173

7b

112

160

70

124

174

7c

113

161

71

125

175

7d

114

162

72

126

176

7e

115

163

73

127

177

7f

^?

[05/03/08]

bash Le livre de recettes

557

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

B
Exemples fournis
avec bash
Le fichier darchive de bash inclut un rpertoire dexemples que vous devez prendre le
temps dexplorer (aprs avoir termin la lecture de ce livre). Il comprend des exemples
de code, de scripts, de fonctions et de fichiers de dmarrage.

Fichiers de dmarrage
Le rpertoire startup-files propose des exemples de fichiers de dmarrage qui peuvent
servir de base aux vtres. En particulier, bash_aliases contient de nombreux alias trs
utiles. Noubliez pas que si vous recopiez directement ces fichiers, vous devrez les adaptez votre systme car plusieurs chemins risquent dtre diffrents. Pour plus dinformations sur la modification de ces fichiers conformment vos besoins, consultez le
chapitre 16, Configurer bash.
Les dfinitions de fonctions du rpertoire functions vous seront certainement utiles.
Vous y trouverez en particulier les suivantes :
basename
Lutilitaire basename, absent de certains systmes.
dirfuncs
Outils de manipulation des rpertoires.
dirname
Lutilitaire dirname, absent de certains systmes.
whatis
Une implmentation de la commande whatis interne au shell Bourne dUnix 10e
dition.
whence
Un clone quasi parfait de la commande whence interne au shell Korn.
Si vous avez dj employ le shell Korn, vous trouverez le fichier kshenv particulirement intressant. Il contient des dfinitions de fonctions pour certains outils Korn classiques, comme whence, print et la commande interne cd deux paramtres.
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

560

Annexe B Exemples fournis avec bash

Les exemples de scripts bash se trouvent dans le rpertoire scripts. Les deux les plus importants prsentent toutes les oprations complexes que vous pouvez raliser avec des
scripts shell. Le premier est un interprteur de jeu daventure et le second un interprteur de shell C. Les autres scripts implmentent des rgles de prcdence, un affichage
de texte dfilant, une roue tournante reprsentant la progression dun processus et
une solution pour inviter lutilisateur fournir un certain type de rponse.
Non seulement ces scripts et ces fonctions peuvent tre intgrs votre environnement,
mais ils constituent galement un bon support pour complter vos connaissances. Nous
vous encourageons les tudier.
Le tableau B-1 servira dindex au contenu de larchive de bash version 3.1 ou ultrieure.
Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure
Chemin

Description

./bashdb

Exemple dimplmentation obsolte dun dbogueur bash.

./complete

Code de compltion du shell.

./functions

Exemples de fonctions.

./functions/array-stuff

Fonctions
pour
les
array_sort, reverse).

./functions/array-to-string

Convertir un tableau en une chane.

./functions/autoload

Une version presque compatible avec ksh de ksh


autoload (sans le chargement paresseux).

./functions/autoload.v2

Une version presque compatible avec ksh de ksh


autoload (sans le chargement paresseux).

./functions/autoload.v3

Une version plus compatible avec ksh de ksh


autoload (avec le chargement paresseux).

./functions/basename

Remplaant pour basename(1).

./functions/basename2

Fonctions basename(1) et dirname(1) rapides basename,


pour bash/sh.
dirname

./functions/coproc.bash

Dmarrer, grer et terminer des co-processus.

./functions/coshell.bash

Grer les co-processus


coprocess.bash).

./functions/coshell.README

README pour coshell et coproc.

./functions/csh-compat

Paquetage de compatibilit avec le shell C.

./functions/dirfuncs

Fonctions de manipulation des rpertoires tires


du livre The Korn Shell.

./functions/dirname

Remplaant pour dirname(1).

./functions/emptydir

Dterminer si un rpertoire est vide.

./functions/exitstat

Afficher le code de sortie des processus.

./functions/external

Comme command, mais force lutilisation dune


commande externe.

[05/03/08]

bash Le livre de recettes

Voir aussi

tableaux

du

(ashift,

basename

shell

(voir

csh

dirname

Elodie FRITSCH <elodie.fritsch@total.com>

Fichiers de dmarrage

561

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin

Description

./functions/fact

Fonction rcursive de calcul dune factorielle.

./functions/fstty

Interface pour synchroniser les modifications de stty.bash


TERM avec stty(1) et bind de readline.

./functions/func

Afficher les dfinitions des fonctions nommes


en argument.

./functions/gethtml

Obtenir une page web depuis un serveur distant


(wget(1) dans bash).

./functions/getoptx.bash

Fonction getopt qui analyse les options donnes


sous forme de noms longs.

./functions/inetaddr

Conversion dune adresse internet (inet2hex et


hex2inet).

./functions/inpath

Retourner zro si largument se trouve dans le inpath


chemin et sil est excutable.

./functions/isnum.bash

Vrifier si la saisie de lutilisateur est une valeur


numrique ou un caractre.

./functions/isnum2

Vrifier si la saisie de lutilisateur est une valeur


numrique, en virgule f lottante.

./functions/isvalidip

Vrifier si la saisie de lutilisateur est une adresse


IP valide.

./functions/jdate.bash

Conversion de date ordinale.

./functions/jj.bash

Rechercher des tches en cours dexcution.

./functions/keep

Tenter de garder certains programmes au premier plan et en excution.

./functions/ksh-cd

Commande cd de type ksh : cd


[change]].

[-LP]

[rp ksh

./functions/ksh-compat-test

Test arithmtique de type ksh.

./functions/kshenv

Fonctions et alias pour obtenir le dbut dun ksh


environnement ksh sous bash.

./functions/login

Remplacer les commandes internes login et


newgrp des anciens shells Bourne.

./functions/lowercase

Renommer les fichiers en minuscules.

rename lower

./functions/manpage

Trouver et afficher une page de manuel.

fman

./functions/mhfold

Afficher les dossiers MH, utile uniquement


parce que folders(1) naffiche pas les dates et heures de modification.

./functions/notify.bash

Indiquer les changements dtat des tches.

./functions/pathfuncs

Fonctions de gestion du chemin (no_path, path


add_path, pre-path, del_path).

ksh

./functions/README

README.

./functions/recurse

Parcourir rcursivement un rpertoire.

./functions/repeat2

Clone de la commande repeat interne au shell C. repeat, csh

./functions/repeat3

Clone de la commande repeat interne au shell C. repeat, csh

[05/03/08]

bash Le livre de recettes

Voir aussi

Elodie FRITSCH <elodie.fritsch@total.com>

562

Annexe B Exemples fournis avec bash

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin

Description

./functions/seq

Gnrer une suite de m n ; m vaut par dfaut 1.

./functions/seq2

Gnrer une suite de m n ; m vaut par dfaut 1.

./functions/shcat

Affichage pagin bas sur Readline.

cat, readline
pager

./functions/shcat2

Affichage pagin bas sur Readline.

cat, readline
pager

./functions/sort-pos-params

Trier les paramtres positionnels.

./functions/substr

Fonction dmulation de lancienne commande ksh


interne de ksh.

./functions/substr2

Fonction dmulation de lancienne commande ksh


interne de ksh.

./functions/term

Fonction qui fixe le type de terminal de manire


interactive ou non.

./functions/whatis

Implmentation de la commande whatis(1)


interne sh pour Unix 10e dition.

./functions/whence

Version presque compatible avec ksh de la commande whence(1).

./functions/which

muler la commande which(1) telle quelle


existe dans FreeBSD.

./functions/xalias.bash

Convertir des commandes et alias csh en fonc- csh, aliasconv


tions bash.

./functions/xfind.bash

Clone de find(1).

./loadables/

Exemples de remplaants chargeables.

./loadables/basename.c

Retourner le nom de chemin sans la partie basename


rpertoire.

./loadables/cat.c

Remplaant de cat(1) sans option la version cat, readline


normale de cat.
pager

./loadables/cut.c

Remplaant de cut(1).

./loadables/dirname.c

Retourner la partie rpertoire du nom de che- dirname


min.

./loadables/finfo.c

Afficher des informations sur le fichier.

./loadables/getconf.c

Utilitaire getconf POSIX.2

./loadables/getconf.h

Dfinitions de remplacement pour celles non


fournies par le systme.

./loadables/head.c

Copier la premire partie des fichiers.

./loadables/hello.c

Exemple Hello World indispensable.

./loadables/id.c

Identit POSIX.2 de lutilisateur.

./loadables/ln.c

Crer des liens.

./loadables/logname.c

Afficher le nom de connexion de lutilisateur


courant.

[05/03/08]

bash Le livre de recettes

Voir aussi

Elodie FRITSCH <elodie.fritsch@total.com>

Fichiers de dmarrage

563

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin

Description

./loadables/Makefile.in

Fichier makefile simple pour les exemples de


commandes internes chargeables.

./loadables/mkdir.c

Crer des rpertoires.

./loadables/necho.c

echo sans options ni interprtation des arguments.

./loadables/pathchk.c

Vrifier la validit et la portabilit des noms de


chemins.

./loadables/print.c

Commande interne print chargeable de type ksh93.

./loadables/printenv.c

Clone minimal de la commande printenv(1) de


BSD.

./loadables/push.c

Qui se souvient de TOPS-20 ?

./loadables/README

README.

./loadables/realpath.c

Obtenir des noms de chemins canoniques, en


rsolvant les liens symboliques.

./loadables/rmdir.c

Supprimer un rpertoire.

./loadables/sleep.c

Attendre pendant des fractions de seconde.

./loadables/strftime.c

Interface interne chargeable pour strftime(3).

./loadables/sync.c

Synchroniser les disques en forant les critures


en attente.

./loadables/tee.c

Dupliquer lentre standard.

./loadables/template.c

Modle de commande interne chargeable.

./loadables/truefalse.c

Commandes internes true et false.

./loadables/tty.c

Retourner le nom du terminal.

./loadables/uname.c

Afficher des informations sur le systme.

./loadables/unlink.c

Supprimer lentre dun rpertoire.

./loadables/whoami.c

Afficher le nom de lutilisateur courant.

./loadables/perl/

Comment implmenter un interprteur Perl en


bash.

./misc

Divers.

./misc/aliasconv.bash

Convertir des alias csh en alias et fonctions bash. csh, xalias

./misc/aliasconv.sh

Convertir des alias csh en alias et fonctions bash. csh, xalias

./misc/cshtobash

Convertir des alias, des variables denvironne- csh, xalias


ment et des variables csh en quivalents bash.

./misc/README

README.

./misc/suncmd.termcap

Chane TERMCAP de SunView.

[05/03/08]

bash Le livre de recettes

Voir aussi

Elodie FRITSCH <elodie.fritsch@total.com>

564

Annexe B Exemples fournis avec bash

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin

Description

./obashdb

Version modifie du dbogueur du shell Korn


tire du livre Learning the Korn Shell de Bill
Rosenblatt.

./scripts.noah

Ensemble de scripts de Noah Friedman (mis


jour avec la syntaxe de bash v2 par Chet Ramey).

./scripts.noah/aref.bash

Exemples de pseudo-tableaux et dindices de


sous-chanes.

./scripts.noah/bash.sub.bash

Fonctions employes par require.bash.

Voir aussi

./scripts.noah/bash_version.bash Fonction de dcomposition de $BASH_VERSION.


./scripts.noah/meta.bash

Activer et dsactiver lentre sur 8 bits dans


readline.

./scripts.noah/mktmp.bash

Crer un fichier temporaire avec un nom unique.

./scripts.noah/number.bash

Convertir des nombres en anglais.

./scripts.noah/PERMISSION

Autorisations dutilisation des scripts de ce


rpertoire.

./scripts.noah/prompt.bash

Une manire de fixer PS1 des chanes prdfinies.

./scripts.noah/README

README.

./scripts.noah/remap_keys.bash

Interface bind pour refaire des liaisons readline. readline

./scripts.noah/require.bash

Fonctions Lisp require / provide pour


bash.

./scripts.noah/send_mail.bash

Client SMTP crit en bash.

./scripts.noah/shcat.bash

Remplaant bash de cat(1).

./scripts.noah/source.bash

Remplaant de source qui utilise le rpertoire de


travail.

./scripts.noah/string.bash

Les fonctions string(3) au niveau du shell.

./scripts.noah/stty.bash

Interface stty(1) qui modifie galement les fstty


liaisons de readline.

./scripts.noah/y_or_n_p.bash

Invite pour une rponse de type oui/non/quit- ask


ter.

./scripts.v2

Ensemble de scripts ksh de John DuBois (convertis la syntaxe de bash v2 par Chet Ramey).

./scripts.v2/arc2tarz

Convertir une archive arc en une archive tar


compresse.

./scripts.v2/bashrand

Gnrateur de nombres alatoires avec des bor- random


nes suprieures et infrieures, ainsi quune
graine facultative.

./scripts.v2/cal2day.bash

Convertir un numro de jour en un nom.

[05/03/08]

bash Le livre de recettes

cat

Elodie FRITSCH <elodie.fritsch@total.com>

Fichiers de dmarrage

565

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin

Description

./scripts.v2/cdhist.bash

Remplaant de cd acceptant une pile de rpertoires.

./scripts.v2/corename

Indiquer lorigine dun fichier core.

./scripts.v2/fman

Remplaant rapide de man(1).

./scripts.v2/frcp

Copier des fichiers avec ftp(1), mais avec une


syntaxe de type rcp.

./scripts.v2/lowercase

Passer des noms de fichiers en minuscules.

./scripts.v2/ncp

Interface agrable pour cp(1) (avec -i, etc.).

./scripts.v2/newext

Modifier lextension dun ensemble de fichiers.

rename

./scripts.v2/nmv

Interface agrable pour mv(1) (avec -i, etc.).

rename

./scripts.v2/pages

Afficher les pages indiques des fichiers.

./scripts.v2/PERMISSION

Autorisations dutilisation des scripts de ce


rpertoire.

./scripts.v2/pf

Affichage pagin qui gre les fichiers compresss.

./scripts.v2/pmtop

top(1) pour SunOS 4.x et BSD/OS.

./scripts.v2/README

README.

./scripts.v2/ren

Renommer des fichiers en modifiant les parties rename


qui correspondent un motif.

./scripts.v2/rename

Changer les noms des fichiers qui correspondent rename


un motif.

./scripts.v2/repeat

Excuter plusieurs fois une commande.

./scripts.v2/shprof

Profileur de ligne pour les scripts bash.

./scripts.v2/untar

Extraire une archive tar (potentiellement compresse) dans un rpertoire.

./scripts.v2/uudec

uudecode(1) prudent pour plusieurs fichiers.

./scripts.v2/uuenc

uuencode(1) pour plusieurs fichiers.

./scripts.v2/vtree

Afficher une reprsentation graphique dune tree


arborescence de rpertoires.

./scripts.v2/where

Afficher lemplacement des commandes qui correspondent un motif.

./scripts

Exemples de scripts.

./scripts/adventure.sh

Jeu daventure en bash !

./scripts/bcsh.sh

mulateur de shell C.

csh

./scripts/cat.sh

Affichage pagin bas sur Readline.

cat, readline
pager

./scripts/center

Centrer un groupe de lignes.

./scripts/dd-ex.sh

diteur de ligne qui utilise uniquement /bin/sh,


/bin/dd et /bin/rm.

[05/03/08]

bash Le livre de recettes

Voir aussi

manpage

rename lower

repeat

Elodie FRITSCH <elodie.fritsch@total.com>

566

Annexe B Exemples fournis avec bash

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin

Description

./scripts/fixfiles.bash

Parcourir rcursivement une arborescence et


corriger les fichiers qui contiennent diffrents
caractres invalides.

./scripts/hanoi.bash

Les invitables Tours de Hano en bash.

./scripts/inpath

Rechercher dans $PATH un fichier de mme nom inpath


que $1 ; retourner TRUE sil est trouv.

./scripts/krand.bash

Gnrer un nombre alatoire avec des bornes random


entires.

./scripts/line-input.bash

Routine de saisie de ligne pour le Bourne Again


Shell de GNU avec les primitives de contrle du
terminal.

./scripts/nohup.bash

Version bash de la commande nohup.

./scripts/precedence

Tester la prcdence relative pour les oprateurs


&& et ||.

./scripts/randomcard.bash

Afficher une carte alatoire tire depuis un jeu random


de cartes.

./scripts/README

README.

./scripts/scrollbar

Afficher du texte dfilant.

./scripts/scrollbar2

Afficher du texte dfilant.

./scripts/self-repro

Un script qui sauto-reproduit (prudence !).

./scripts/showperm.bash

Convertir les autorisations symboliques de ls(1)


en mode octal.

./scripts/shprompt

Afficher une invite et obtenir une rponse con- ask


forme certains critres.

./scripts/spin.bash

Afficher une roue tournante reprsentant une


progression.

./scripts/timeout

Appliquer rsh(1) une temporisation plus


courte.

./scripts/vtree2

Afficher une arborescence de rpertoires avec tree


loccupation du disque en blocs de 1k.

./scripts/vtree3

Afficher une reprsentation graphique dune tree


arborescence de rpertoires.

./scripts/vtree3a

Afficher une reprsentation graphique dune tree


arborescence de rpertoires.

./scripts/websrv.sh

Un serveur web en bash !

./scripts/xterm_title

Afficher le contenu de la barre de titre de xterm.

./scripts/zprintf

muler printf (obsolte puisque printf est dsormais une commande interne de bash).

./startup-files

Exemples de fichiers de dmarrage.

./startup-files/Bash_aliases

Quelques alias utiles (crits par Fox).

[05/03/08]

bash Le livre de recettes

Voir aussi

Elodie FRITSCH <elodie.fritsch@total.com>

Fichiers de dmarrage

567

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin

Description

./startup-files/Bash_profile

Fichier de dmarrage pour un shell bash


douverture de session (crit par Fox).

./startup-files/bash-profile

Fichier de dmarrage pour un shell bash


douverture de session (crit par Ramey).

./startup-files/bashrc

Fichier init pour le Bourne Again Shell (crit par


Ramey).

./startup-files/Bashrc.bfox

Fichier init pour le Bourne Again Shell (crit par


Fox).

./startup-files/README

README.

./startup-files/apple

Exemples de fichiers de dmarrage Mac OS X.

./startup-files/apple/aliases

Alias pour Mac OS X.

./startup-files/apple/
bash.defaults

Fichier des prfrences de lutilisateur pour Mac


OS X.

Voir aussi

./startup-files/apple/environment Fichier denvironnement pour le Bourne Again


Shell.
./startup-files/apple/login

Enveloppe douverture de session.

./startup-files/apple/logout

Enveloppe de fermeture de session.

./startup-files/apple/rc

Fichier de configuration pour le Bourne Again


Shell.

./startup-files/apple/README

README.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

C
Analyse de la ligne de
commande
Tout au long de ce livre, nous avons vu diverses manires de traiter les lignes dentre,
en particulier en utilisant read. Vous pouvez voir ce processus comme un sous-ensemble des oprations effectues par le shell lors du traitement de la ligne de commande.
Cette annexe propose une description plus dtaille des tapes de ce processus et explique comment faire en sorte que bash effectue une seconde passe avec eval. Son contenu
apparat galement dans le livre Le shell bash, 3e dition de Cameron Newham et Bill Rosenblatt (ditions OReilly).

tapes du traitement de la ligne de commande


Nous avons dj abord le traitement de la ligne de commande dans ce livre. Nous
avons vu comment bash traite les apostrophes (''), les guillemets("") et les barres obliques inverses (\), comment il dcoupe les lignes en mots, selon les dlimiteurs dans la
variable denvironnement $IFS, comment il attribue les mots des variables shell (par
exemple, $1, $2, etc.) et comment il redirige lentre et la sortie depuis/vers des fichiers
ou dautres processus (tube). Pour devenir un vritable expert des scripts shell (ou pour
dboguer des problmes ardus), vous aurez besoin de comprendre les diffrentes tapes
du traitement de la ligne de commande, en particulier lordre des oprations.
Chaque ligne lue par le shell sur lentre standard ou un script est appele tube car elle
contient une ou plusieurs commandes spares par zro ou plusieurs symboles du tube
(|). La figure C-1 montre les tapes du traitement de la ligne de commande. Chaque tube
lu est dcompos par le shell en commandes, il configure ses entres/sorties et ralise
ensuite les actions suivantes pour chaque commande :
1. La commande est dcompose en jetons spars par un ensemble dfini de mtacaractres : espace, tabulation, saut de ligne, ;, (, ), <, >, | et &. Les types de jetons
reconnus sont les mots, les mots-cls, les oprateurs de redirection dE/S et les
points-virgules.
2. Le premier jeton de chaque commande est test afin de savoir sil sagit dun motcl sans apostrophe ou une barre oblique inverse. Si ce jeton nest pas un mot-cl
douverture, comme if et dautres premiers lments de structure de contrle,
function, { ou (, alors la commande est en ralit une commande compose. Le shell
[05/03/08]
Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

570

Annexe C Analyse de la ligne de commande

Figure C-1. tapes du traitement de la ligne de commande

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

tapes du traitement de la ligne de commande

571

configure ses structures internes pour la commande compose, lit la commande


suivante et relance le processus. Si le mot-cl nest pas le dbut dune commande
compose (par exemple, il sagit dun mot-cl intermdiaire de la structure comme
then, else ou do, dun mot-cl final comme fi ou done ou dun oprateur logique),
le shell signale une erreur de syntaxe.
3. Le premier mot de chaque commande est compar la liste des alias. Si une correspondance est trouve, la substitution est effectue et le shell revient ltape 1 ;
sinon, le shell passe ltape 4. Ce fonctionnement permet de proposer les alias
rcursifs. Il permet galement de dfinir des alias pour des mots-cls, par exemple
alias tantque=while ou alias procedure=function.
4. Le dveloppement des accolades est ralis. Par exemple, a{b,c} devient ab ac.
5. Le rpertoire daccueil de lutilisateur ($HOME) remplace le tilde sil se trouve au
dbut dun mot. Le rpertoire daccueil de lutilisateur remplace ~utilisateur.
6. La substitution de paramtre (variable) est effectue pour toute expression qui
commence par un symbole dollar ($).
7. La substitution de commande est effectue pour toute expression de la forme
$(chane).
8. Les expressions arithmtiques de la forme $((chane)) sont values.
9. Les parties de la ligne rsultant de la substitution de paramtre, de la substitution
de commande et de lvaluation arithmtique sont nouveau dcomposes en
mots. Cette fois-ci, les caractres de $IFS sont utiliss comme dlimiteurs la place
de lensemble de mta-caractres pris ltape 1.
10. Lexpansion de nom de chemin (expansion des caractres gnriques) est effectue
pour toute occurrence de *, de ? et de paires [/].
11. Le premier mot est employ comme une commande en recherchant son source
dans lordre suivant : comme une fonction, puis une commande interne et enfin
comme un fichier dans lun des rpertoires indiqus par $PATH.
12. La commande est excute aprs avoir configur la redirection des entres/sorties et
autres aspects similaires.
Cela reprsente de nombreuses tapes et, pourtant, le processus nest pas complet !
Avant de poursuivre, un exemple permettra de clarifier les choses. Supposons que la
commande suivante soit lance :
alias ll="ls -l"

Supposons galement quil existe un fichier .hist537 dans le rpertoire daccueil de alice,
cest--dire /home/alice, et quil existe une variable avec deux symboles dollars $$ dont la
valeur est 2537 ($$ contient lidentifiant de processus, un nombre unique parmi tous les
processus en cours dexcution).
Voyons maintenant comment le shell traite la commande suivante :
ll $(type -path cc) ~alice/.*$(($$%1000))

Voici ce qui arrive cette ligne :


1. ll $(type -path cc) ~alice/.*$(($$%1000))
Lentre est dcompose en mots.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

572

Annexe C Analyse de la ligne de commande

2. ll nest pas un mot-cl, ltape 2 ne donne donc rien.


3. ls -l $(type -path cc) ~alice/.*$(($$%1000))
ll est remplac par son alias ls -l. Le shell rpte ensuite les tapes 1 3 ; ltape 2
dcompose ls -l en deux mots.
4. ls -l $(type -path cc) ~alice/.*$(($$%1000))
Cette tape ne donne rien.
5. ls -l $(type -path cc) /home/alice/.*$(($$%1000))
~alice est converti en /home/alice.
6. ls -l $(type -path cc) /home/alice/.*$((2537%1000))
$$ est remplac par 2537.
7. ls -l /usr/bin/cc /home/alice/.*$((2537%1000))
La substitution de commande est effectue pour type -path cc.
8. ls -l /usr/bin/cc /home/alice/.*537
Lexpression arithmtique 2537%1000 est value.
9. ls -l /usr/bin/cc /home/alice/.*537
Cette tape ne donne rien.
10. ls -l /usr/bin/cc /home/alice/.hist537
Lexpression avec caractre gnrique .*537 est remplace par le nom de fichier.
11. La commande ls est trouve dans /usr/bin.
12. /usr/bin/ls est excute avec loption -l et les deux arguments.
Bien que cette liste dtapes soit assez directe, le processus nest pas complet. Il existe encore cinq manires de modifier le processus : protection, utilisation de command, builtin ou enable et utilisation de la commande avance eval.

Protection
Vous pouvez voir la protection comme une manire dviter au shell certaines des douze tapes prcdentes. En particulier :

Les apostrophes ('') vitent les dix premires tapes, y compris le traitement des
alias. Tous les caractres placs entre deux apostrophes restent inchangs. Il nest
pas possible de placer une apostrophe entre des apostrophes, mme en la prcdant
dune barre oblique inverse.

Les guillemets ("") vitent les tapes 1 4, ainsi que les tapes 9 et 10. Autrement
dit, les caractres de tube, les alias, la substitution du tilde, lexpansion des caractres gnriques et la dcomposition en mots via les dlimiteurs (par exemple les
espaces) sont ignors lintrieur des guillemets. Les apostrophes lintrieur des
guillemets nont aucun effet. Mais les guillemets autorisent la substitution de paramtre, la substitution de commande et lvaluation des expressions arithmtiques.
Vous pouvez inclure des guillemets lintrieur dune chane entoure de guillemets en les faisant prcder dune barre oblique inverse (\). Vous devez galement

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

tapes du traitement de la ligne de commande

573

appliquer lchappement $, ` (lancien dlimiteur de substitution de commande) et \ lui-mme.


Le tableau C-1 donne des exemples simples illustrant ce fonctionnement ; il suppose que
linstruction personne=chapelier a t excute et que le rpertoire daccueil de lutilisateur alice est /home/alice.
Si vous vous demandez sil faut utiliser des apostrophes ou des guillemets dans un cas
particulier, il est plus sr dutiliser les apostrophes sauf si vous avez besoin de la substitution de paramtre, de commande ou arithmtique.
Tableau C-1. Exemples de protection avec les apostrophes et les guillemets
Expression

Valeur

$personne

chapelier

"$personne"

chapelier

\$personne

$personne

`$personne'

$personne

"'$personne'"

chapelier

~alice

/home/alice

"~alice"

~alice

`~alice'

~alice

eval
Nous avons vu que la protection permet dviter des tapes dans le traitement de la ligne
de commande. Il existe galement la commande eval, qui permet de reprendre le processus. Il peut sembler trange de vouloir raliser deux fois le traitement de la ligne de
commande, mais cette fonctionnalit est en ralit trs puissante : elle permet dcrire
des scripts qui crent des chanes de commande la vole et les passent ensuite au shell
afin quil les excute. Cela signifie que vous pouvez donner aux scripts une intelligence qui leur permet de modifier leur comportement au cours de leur excution.
Linstruction eval demande au shell de prendre ses arguments et de les excuter en droulant les tapes de traitement de la ligne de commande. Pour que vous compreniez
mieux les implications de eval, nous allons commencer par un exemple trivial, pour
arriver la construction et lexcution de commandes la vole.
eval ls passe la chane ls au shell afin quil lexcute ; le shell affiche la liste des fichiers du rpertoire courant. Trs simple ; la chane ls ne contient rien qui doit tre
soumis deux fois aux tapes du traitement de la ligne de commande. Mais, prenons
lexemple suivant :
listerpage="ls | more"
$listerpage

Au lieu de produire une liste de fichiers pagine, le shell traite | et more comme des arguments de ls et cette commande se plaindra quaucun fichier de ce nom existe. Pourquoi ? Le caractre de cration dun tube apparat ltape 6, lorsque le shell value la
variable, aprs la recherche de ces caractres. Lexpansion de la variable nest pas ralise

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

574

Annexe C Analyse de la ligne de commande

avant ltape 9. Ainsi, le shell traite | et more comme des arguments de ls et cette commande tente de trouver des fichiers nomms | et more dans le rpertoire courant !
Examinons maintenant la commande eval $listerpage la place de $listerpage.
Lorsque le shell arrive la dernire tape, il excute la commande eval avec les arguments ls, | et more. Le shell revient alors ltape 1 avec une ligne constitue de ces arguments. Il trouve | ltape 2 et dcompose la ligne en deux commandes, ls et more.
Chaque commande est traite de manire normale. Le rsultat est une liste pagine des
fichiers du rpertoire courant.
Vous devez prsent commencer envisager tout lintrt de eval. Il sagit dune fonctionnalit avance qui ncessite une trs bonne exprience de la programmation pour
tre utilise de faon efficace. Elle montre mme un lger got dintelligence artificielle,
car elle vous permet dcrire des programmes qui peuvent crire et excuter dautres
programmes. Vous nutiliserez probablement pas eval dans vos programmes shell classique, mais cela vaut la peine de comprendre ce quelle peut vous apporter.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

D
Gestion de versions

Les systmes de gestion de versions sont non seulement un moyen de remonter dans le
temps, mais galement de connatre les modifications apportes diffrents moments
du dveloppement. Ils vous permettent dadministrer un dpt centralis o sont stocks les fichiers dun projet et de conserver une trace des modifications, ainsi que les raisons de ces changements. Certains autorisent plusieurs dveloppeurs travailler en
parallle sur le mme projet, voire sur le mme fichier.
Ces systmes sont indispensables pour le dveloppement des logiciels, mais ils sont galement utiles dans de nombreux autres domaines, comme la rdaction dune documentation, le suivi des configurations dun systme (par exemple, /etc) o lcriture de livres.
Les diffrentes versions de cet ouvrage ont t sous le contrle de Subversion.
Voici les principaux avantages des systmes de gestion de versions :

il est trs difficile de perdre du code, en particulier lorsque le dpt est correctement sauvegard ;

la gestion des modifications est facilite et la documentation de leur raison dtre


est encourage ;

plusieurs personnes peuvent travailler ensemble sur un projet et suivre les modifications apportes par chacune, sans perdre des donnes par crasement de fichiers ;

une personne peut changer de lieu de travail au fil du temps sans avoir recommencer ce quelle a fait ailleurs ;

il est facile de revenir des modifications antrieures ou de savoir prcisment ce


qui a volu entre deux versions (except pour les fichiers binaires). Si vous suivez
les rgles de base de la journalisation, vous saurez mme pourquoi une modification a t effectue ;

en gnral, il existe une forme dexpansion de mot-cl qui permet dinclure des
informations de version dans les fichiers non binaires.

Il existe plusieurs systmes de gestion de versions, certains gratuits, dautres commerciaux, et nous vous conseillons fortement den utiliser un. Si ce nest pas dj le cas, nous
allons brivement dcrire trois des systmes les plus rpandus (CVS, Subversion et
RCS), qui sont livrs ou disponibles pour tous les principaux systmes dexploitation
modernes.
[05/03/08]
Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

576

Annexe D Gestion de versions

Avant demployer un systme de gestion de versions, vous devez commencer par faire
certains choix :

quel systme ou produit utiliser ;

lemplacement du dpt central, si ncessaire ;

la structure des projets ou des rpertoires dans le dpt ;

les politiques de mise jour, de validation, de balisage et de cration des branches.

Cette annexe ne fait quaborder ce thme. Pour une description plus dtaille, consultez
les livres Essential CVS de Jennifer Vesperman (OReilly Media) et Gestion de projets avec
Subversion de Ben Collins-Sussman et autres (ditions OReilly). Tous deux prsentent
trs bien les concepts gnraux, mme si louvrage sur Subversion explique de manire
plus dtaille la structure dun dpt.
Ces deux livres traitent galement des stratgies de gestion des versions. Si votre socit
en a tabli certaines, utilisez-les. Dans le cas contraire, nous vous conseillons deffectuer
les validations et les mises jour au plus tt et trs souvent. Si vous travaillez au sein
dune quipe, nous vous recommandons fortement de lire ces ouvrages, ou au moins
lun deux, et de planifier soigneusement une stratgie. Cela vous permettra de gagner
beaucoup de temps sur le long terme.

CVS
CVS (Concurrent Versions System) est un systme de gestion de versions mature et trs largement employ. Il dispose doutils en ligne de commande pour tous les principaux systmes dexploitation modernes, y compris Windows, et des outils graphiques pour
certains dentre eux, en particulier Windows.

Avantages

il est omniprsent et trs mature ;

de nombreux administrateurs systme Unix et pratiquement tout dveloppeur de


logiciels Open Source ou gratuit le connaissent ;

il est facile employer pour les projets simples ;

laccs aux dpts distants est ais ;

il sappuie sur RCS, qui autorise une intervention directement sur le dpt central.

Inconvnients

les validations ne sont pas atomiques et le dpt peut donc se trouver dans un tat
incohrent lorsquune validation choue en cours de route ;

les validations se font uniquement par fichier ; vous devez utiliser un balisage pour
rfrencer un groupe de fichiers ;

la prise en charge des structures de rpertoires est peu labore ;

il nest pas facile de renommer des fichiers ou des rpertoires tout en conservant
lhistorique ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

CVS

577

la prise en charge des fichiers binaires est pauvre, tout comme celle des autres
objets tels que les liens symboliques ;

il sappuie sur RCS, qui autorise une intervention directement sur le dpt central.
Dans CVS, le suivi des versions se fait fichier par fichier. Autrement dit,
chaque fichier possde son propre numro de version CVS interne.
Lorsquun fichier est modifi, ce numro change et il est donc impossible de donner un seul numro de version un mme projet. Pour mettre en place ce type de suivi, utilisez un balisage.

Exemple
Cet exemple nest pas adapt une socit ou un accs multi-utilisateurs (voir la section
Autres ressources, page xix). Il sagit uniquement dillustrer les bases de CVS. Pour cet
exemple, la variable denvironnement EDITOR choisit lditeur nano (export EDITOR=
'nano --smooth --const --nowrap --suspend'), que certaines personnes trouvent plus
convivial que lditeur vi par dfaut.
La commande cvs (sans options), la commande cvs help (help nest pas un argument
valide, mais il est facile mmoriser et produit une rponse intressante) et la commande cvs --help commande_cvs sont trs utiles.
Crez un nouveau dpt pour votre propre utilisation dans votre rpertoire personnel :
/home/jp$ mkdir -m 0775 cvsroot
/home/jp$ chmod g+srwx cvsroot
/home/jp$ cvs -d /home/jp/cvsroot init

Crez un nouveau projet et importez-le :


/home/jp$ cd /tmp
/tmp$ mkdir 0700 scripts
/tmp$ cd scripts/
/tmp/scripts$ cat << EOF > bonjour
> #!/bin/sh
> echo 'Bonjour tout le monde !'
> EOF
/tmp/scripts$ cvs -d /home/jp/cvsroot import scripts scripts_shell NA
GNU nano 1.2.4

File: /tmp/cvsnJgYmG

Importation initiale des scripts shell.


CVS: ---------------------------------------------------------------------CVS: Enter Log. Lines beginning with `CVS:' are removed automatically
CVS:
CVS: ---------------------------------------------------------------------[ Wrote 5 lines ]
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

578

Annexe D Gestion de versions

N scripts/bonjour
No conflicts created by this import

Vrifiez le projet et mettez-le jour :


/tmp/scripts$ cd
/home/jp$ cvs -d /home/jp/cvsroot/ checkout scripts
cvs checkout: Updating scripts
U scripts/bonjour
/home/jp$ cd scripts
/home/jp/scripts$ ls -l
total 8.0K
drwxr-xr-x 2 jp jp 4.0K Jul 20 00:27 CVS/
-rw-r--r-- 1 jp jp 41 Jul 20 00:25 bonjour
/home/jp/scripts$ echo "Salut M'man..." >> bonjour

Vrifiez ltat de votre bac sable. La deuxime commande est une astuce qui permet
dobtenir un court rsum de ltat si vous trouvez la premire un peu verbeuse :
/home/jp/scripts$ cvs status
cvs status: Examining .
===================================================================
File: bonjour
Status: Locally Modified
Working revision:
Repository revision:
Sticky Tag:
Sticky Date:
Sticky Options:

1.1.1.1 Thu Jul 20 04:25:44 2006


1.1.1.1 /home/jp/cvsroot/scripts/bonjour,v
(none)
(none)
(none)

/home/jp/scripts$ cvs -qn update


M bonjour

Ajoutez un nouveau script au contrle de versions :


/home/jp/scripts$ cat << EOF > mcd
> #!/bin/sh
> mkdir -p "$1"
> cd "$1"
> EOF
/home/jp/scripts$ cvs add mcd
cvs add: scheduling file `mcd' for addition
cvs add: use `cvs commit' to add this file permanently

Validez les modifications :


/home/jp/scripts$ cvs commit
cvs commit: Examining .
GNU nano 1.2.4

[05/03/08]

bash Le livre de recettes

File: /tmp/cvsY1xcKa

Elodie FRITSCH <elodie.fritsch@total.com>

CVS

579

* bonjour a t modifi.
* mcd a t ajout.
CVS: ---------------------------------------------------------------------CVS: Enter Log. Lines beginning with `CVS:' are removed automatically
CVS:
CVS: Committing in .
CVS:
CVS: Modified Files:
CVS:
bonjour
CVS: Added Files:
CVS:
mcd
CVS: ---------------------------------------------------------------------[ Wrote 12 lines ]
/home/jp/cvsroot/scripts/hello,v <-- hello
new revision: 1.2; previous revision: 1.1
/home/jp/cvsroot/scripts/mcd,v <-- mcd
initial revision: 1.1

Actualisez le bac sable, apportez une autre modification, puis vrifiez la diffrence :
/home/jp/scripts$ cvs update
cvs update: Updating .
/home/jp/scripts$ vi bonjour
/home/jp/scripts$ cvs diff bonjour
Index: bonjour
===================================================================
RCS file: /home/jp/cvsroot/scripts/bonjour,v
retrieving revision 1.2
diff -r1.2 bonjour
3c3
< Salut M'man...
--> echo "Salut M'man..."

Validez les modifications, sans passer par lditeur, en ajoutant lentre du journal sur
la ligne de commande :
/home/jp/scripts$ cvs commit -m "* correction de l'erreur de syntaxe."
/home/jp/cvsroot/scripts/bonjour,v <-- bonjour
new revision: 1.3; previous revision: 1.2

Consultez lhistorique du fichier :


/home/jp/scripts$ cvs log bonjour
RCS file: /home/jp/cvsroot/scripts/bonjour,v
Working file: bonjour
head: 1.3
branch:
locks: strict

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

580

Annexe D Gestion de versions

access list:
symbolic names:
NA: 1.1.1.1
scripts_shell: 1.1.1
keyword substitution: kv
total revisions: 4;
selected revisions: 4
description:
---------------------------revision 1.3
date: 2006-07-20 04:46:25 +0000; author: jp; state: Exp; lines: +1 -1
* correction de l'erreur de syntaxe.
---------------------------revision 1.2
date: 2006-07-20 04:37:37 +0000; author: jp; state: Exp; lines: +1 -0
* bonjour a t corrig.
* mcd a t ajout.
---------------------------revision 1.1
date: 2006-07-20 04:25:44 +0000; author: jp; state: Exp;
branches: 1.1.1;
Initial revision
---------------------------revision 1.1.1.1
date: 2006-07-20 04:25:44 +0000; author: jp; state: Exp; lines: +0 -0
Importation initiale des scripts shell.
===========================================================================
==

Ajoutez des informations qui sont automatiquement actualises par le systme de gestion de versions lui-mme. Validez-les et examinez les modifications :
/home/jp/scripts$ vi bonjour
/home/jp/scripts$ cat bonjour
#!/bin/sh
$Id$
echo 'Bonjour tout le monde !'
echo "Salut M'man..."
/home/jp/scripts$ cvs ci -m 'mot-cl ID ajout.' bonjour
/home/jp/cvsroot/scripts/bonjour,v <-- bonjour
new revision: 1.4; previous revision: 1.3
/home/jp/scripts$ cat bonjour
#!/bin/sh
# $Id: bonjour,v 1.4 2006-07-20 04:47:30 jp Exp $
echo 'Bonjour tout le monde !'
echo "Salut M'man..."

Comparez la version actuelle la version r1.2, revenez cette ancienne version (invalide), ralisez votre erreur et revenez la version la plus rcente :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

CVS

581

/home/jp/cvs.scripts$ cvs diff -r1.2 bonjour


Index: bonjour
===================================================================
RCS file: /home/jp/cvsroot/scripts/bonjour,v
retrieving revision 1.2
retrieving revision 1.4
diff -r1.2 -r1.4
1a2
> # $Id: bonjour,v 1.4 2006-07-20 04:47:30 jp Exp $
3c4
< Salut M'man...
--> echo "Salut M'man..."
/home/jp/scripts$ cvs update -r1.2 bonjour
U bonjour
/home/jp/scripts$ cat bonjour
#!/bin/sh
echo 'Bonjour tout le monde !'
Salut M'man...
/home/jp/cvs.scripts$ cvs update -rHEAD bonjour
U bonjour
/home/jp/cvs.scripts$ cat bonjour
#!/bin/sh
# $Id: bonjour,v 1.4 2006-07-20 04:47:30 jp Exp $
echo 'Bonjour tout le monde !'
echo "Salut M'man..."

Voir aussi

man cvs ;

man rcs2log ;

man cvs-pserver ;

le site web officiel de CVS, http://www.nongnu.org/cvs/ ;

la documentation de CVS et le manuel Cederqvist, http://ximbiot.com/cvs/manual/ ;

laccs CVS depuis le bureau de Window, http://www.tortoisecvs.org/ ;

Introduction to CVS , http://linux.oreillynet.com/lpt/a/1420 ;

CVS Administration , http://linux.oreillynet.com/lpt/a/1421 ;

Tracking Changes in CVS , http://linux.oreillynet.com/lpt/a/2443 ;

CVS Third-Party Tools , http://www.onlamp.com/lpt/a/2895 ;

Top 10 CVS Tips, , http://www.oreillynet.com/lpt/a/2015 ;

CVS Branch and Tag Primer , http://www.psc.edu/~semke/cvs_branches.html ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

582

Annexe D Gestion de versions

CVS Best Practices , http://www.tldp.org/REF/CVS-BestPractices/html/index.html ;

CVS Introduction , http://www.commentcamarche.net/cvs-dev/cvs-intro.php3 ;

Introduction CVS , http://ricky81.developpez.com/tutoriel/cvs/introduction/ ;

Le contrle de versions avec CVS, http://www.tuteurs.ens.fr/logiciels/cvs/ ;

Essential CVS de Jennifer Vesperman (OReilly Media) ;

la recette 16.14, Crer un nouveau rpertoire et y aller avec une seule commande, page
398.

Subversion
Daprs son site web, lobjectif du projet Subversion est de dvelopper un systme de
gestion de versions qui soit un remplaant incontournable de CVS au sein de la communaut Open Source . Tout est dit.

Avantages

il est plus rcent que CVS et RCS ;

il est plus simple et plus facile comprendre et utiliser que CVS (un passif moins
lourd) ;

les validations atomiques signifient quelles chouent ou succdent comme un tout


et quil est plus facile de suivre ltat dun projet global comme une seule version ;

laccs distant aux dpts est ais ;

il est facile de renommer des fichiers ou des rpertoires tout en conservant lhistorique ;

les fichiers binaires sont bien pris en charge (sans diff natif), ainsi que les autres
objets comme les liens symboliques ;

lintervention sur le dpt central est officiellement prise en charge, mais moins
vidente.

Inconvnients

il nest pas compatible 100 % avec CVS pour les projets complexes (par exemple,
au niveau des branches et des balises) ;

il peut tre plus complexe compiler ou installer partir de zro du fait de nombreuses dpendances. Il est prfrable dutiliser la version fournie avec le systme
dexploitation.
Dans SVN, le suivi des versions se fait par dpt. Autrement dit, chaque validation possde son propre numro de version SVN interne. Par
consquent, les validations successives effectues par une mme personne peuvent ne pas avoir des numros conscutifs. En effet, la version du dpt global est incrmente chaque fois quune personne
valide ses modifications (peut-tre pour dautres projets).

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Subversion

583

Exemple
Cet exemple nest pas adapt une socit ou un accs multi-utilisateurs (voir la section
Autres ressources, page xix). Il sagit uniquement dillustrer les bases de Subversion. Pour
cet exemple, la variable denvironnement EDITOR choisit lditeur nano (export EDITOR=
'nano --smooth --const --nowrap --suspend'), que certaines personnes trouvent plus
convivial que lditeur vi par dfaut.
Les commandes svn help et svn help help sont trs utiles.
Crez un nouveau dpt pour votre propre utilisation dans votre rpertoire personnel :
/home/jp$ svnadmin --fs-type=fsfs create /home/jp/svnroot

Crez un nouveau projet et importez-le :


/home/jp$ cd /tmp
/tmp$ mkdir -p -m 0700 scripts/tronc scripts/balises scripts/branches
/tmp$ cd scripts/tronc
/tmp/scripts/tronc$ cat << EOF > bonjour
> #!/bin/sh
> echo 'Bonjour tout le monde !'
> EOF
/tmp/scripts/tronc$ cd ..
/tmp/scripts$ svn import /tmp/scripts file:///home/jp/svnroot/scripts
GNU nano 1.2.4

File: svn-commit.tmp

Importation initiale des scripts shell.


--Cette ligne, et les suivantes ci-dessous, seront ignores-A

.
[ Wrote 4 lines ]

Ajout
Ajout
Ajout
Ajout

/tmp/scripts/balises
/tmp/scripts/tronc
/tmp/scripts/tronc/bonjour
/tmp/scripts/branches

Rvision 1 propage.

Vrifiez le projet et mettez-le jour :


/tmp/scripts$ cd
/home/jp$ svn checkout file:///home/jp/svnroot/scripts
A scripts/balises
A scripts/branches

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

584

Annexe D Gestion de versions

A scripts/tronc
A scripts/tronc/hello
Rvision 1 extraite.
/home/jp$ cd scripts
/home/jp/scripts$ ls -l
total 12K
drwxr-xr-x 3 jp jp 4.0K Jul 20 01:12 balises/
drwxr-xr-x 3 jp jp 4.0K Jul 20 01:12 branches/
drwxr-xr-x 3 jp jp 4.0K Jul 20 01:12 tronc/
/home/jp/scripts$ cd tronc/
/home/jp/scripts/tronc$ ls -l
total 4.0K
-rw-r--r-- 1 jp jp 41 Jul 20 01:12 bonjour
/home/jp/scripts/tronc$ echo "Salut M'man..." >> bonjour

Vrifiez ltat de votre bac sable. Notez que la commande svn status est similaire
notre astuce cvs -qn update donne la section CVS, page 576 :
/home/jp/scripts/tronc$ svn info
Chemin : .
URL : file:///home/jp/svnroot/scripts/tronc
Racine du dpt : file:///home/jp/svnroot
UUID du dpt : 29eeb329-fc18-0410-967e-b075d748cc20
Rvision : 1
Type de noeud : rpertoire
Tche programme : normale
Auteur de la dernire modification : jp
Rvision de la dernire modification : 1
Date de la dernire modification : 2006-07-20 01:04:56 -0400 (jeu, 20 jui
2006)
/home/jp/scripts/tronc$ svn status -v
1
1 jp
M
1
1 jp

.
bonjour

/home/jp/scripts/tronc$ svn status


M
bonjour
/home/jp/scripts/tronc$ svn update
la rvision 1.

Ajoutez un nouveau script au contrle de versions :


/home/jp/scripts/tronc$ cat << EOF > mcd
> #!/bin/sh
> mkdir -p "$1"
> cd "$1"
> EOF
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Subversion

585

/home/jp/scripts/tronc$ svn st
?
mcd
M
bonjour
/home/jp/scripts/tronc$ svn add mcd
A
mcd

Validez les modifications :


/home/jp/scripts/tronc$ svn ci
GNU nano 1.2.4

File: svn-commit.tmp

* bonjour a t modifi.
* mcd a t ajout.
--Cette ligne, et les suivantes ci-dessous, seront ignores-A
M

tronc/mcd
tronc/bonjour
[ Wrote 6 lines ]

Envoi
tronc/bonjour
Ajout
tronc/mcd
Transmission des donnes ..
Rvision 2 propage.

Actualisez le bac sable, apportez une autre modification, puis vrifiez la diffrence :
/home/jp/scripts/tronc$ svn up
la rvision 2.
/home/jp/scripts/tronc$ vi bonjour
/home/jp/scripts/tronc$ svn diff bonjour
Index: bonjour
===================================================================
--- bonjour
(rvision 2)
+++ bonjour
(copie de travail)
@@ -1,3 +1,3 @@
#!/bin/sh
echo 'Bonjour tout le monde !'
-Salut M'man...
+echo "Salut M'man..."

Validez les modifications, sans passer par lditeur, en ajoutant lentre du journal sur
la ligne de commande :
/home/jp/scripts/tronc$ svn -m "* correction de l'erreur de syntaxe." commit
Envoi
tronc/bonjour
Transmission des donnes .
Rvision 3 propage.

Consultez lhistorique du fichier :

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

586

Annexe D Gestion de versions

/home/jp/scripts/tronc$ svn log bonjour


-----------------------------------------------------------------------r3 | jp | 2006-07-20 01:23:35 -0400 (jeu, 20 jui 2006) | 1 line
* correction de l'erreur de syntaxe.
-----------------------------------------------------------------------r2 | jp | 2006-07-20 01:20:09 -0400 (jeu, 20 jui 2006) | 3 lines
* bonjour a t modifi.
* mcd a t ajout.
-----------------------------------------------------------------------r1 | jp | 2006-07-20 01:04:56 -0400 (jeu, 20 jui 2006) | 2 lines
Importation initiale des scripts shell.
------------------------------------------------------------------------

Ajoutez des informations de version et demandez au systme de les actualiser. Validezles et examinez les modifications :
/home/jp/scripts$ vi bonjour
/home/jp/scripts$ cat bonjour
#!/bin/sh
# $Id$
echo 'Bonjour tout le monde !'
echo "Salut M'man..."
home/jp/scripts/tronc$ svn propset svn:keywords "Id" bonjour
proprit 'svn:keywords' dfinie sur 'bonjour'
/home/jp/scripts/tronc$ svn ci -m 'mot-cl ID ajout.' bonjour
Envoi
bonjour
Transmission des donnes
Rvision 4 propage.
/home/jp/scripts/tronc$ cat bonjour
#!/bin/sh
# $Id: bonjour 4 2006-07-20 01:30:12 jp $
echo 'Bonjour tout le monde !'
echo "Salut M'man..."

Comparez la version actuelle la version r2, revenez cette ancienne version (invalide),
ralisez votre erreur et revenez la version la plus rcente :
/home/jp/scripts/tronc$ svn diff -r2 bonjour
Index: bonjour
===================================================================
--- bonjour
(rvision 2)
+++ bonjour
(copie de travail)
@@ -1,3 +1,4 @@

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Subversion

587

#!/bin/sh
+# $Id$
echo 'Bonjour tout le monde !'
-Salut M'man...
+echo "Salut M'man..."
Modification de proprits sur bonjour
___________________________________________________________________
Nom : svn:keywords
+ Id
/home/jp/scripts/tronc$ svn update -r2 bonjour
UU bonjour
Actualis la rvision 2.
/home/jp/scripts/tronc$ cat bonjour
#!/bin/sh
echo 'Bonjour tout le monde !'
Salut M'man...
/home/jp/scripts/tronc$ svn update -rHEAD bonjour
UU bonjour
Actualis la rvision 4.
/home/jp/scripts/tronc$ cat bonjour
#!/bin/sh
# $Id: bonjour 4 2006-07-20 01:30:12 jp $
echo 'Bonjour tout le monde !'
echo "Salut M'man..."

Voir aussi

man svn ;

man svnadmin ;

man svndumpfilter ;

man svnlook ;

man svnserve ;

man svnversion ;

le site web de Subversion, http://subversion.tigris.org/ ;

TortoiseSVN : une interface simple SVN depuis lexplorateur, http://tortoisesvn.


tigris.org/ ;

Version Control with Subversion, http://svnbook.red-bean.com/ ;

compilations statiques de SVN pour Solaris, Linux et Mac OS X http://www.uncc.


org/svntools/clients/ ;

Subversion for CVS Users , http://osdir.com/Article203.phtml ;

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

588

Annexe D Gestion de versions

une comparaison des systmes de gestion de versions, http://better-scm.berlios.de/


comparison/comparison.html ;

Gestion de projets avec Subversion, 1re dition de Ben Collins-Sussman, Brian W. Fitzpatrick et C. Michael Pilato (ditions OReilly) ;

Passer de CVS Subversion , http://www.journaldunet.com/developpeur/tutoriel/out/060127-passer-de-cvs-a-subversion.shtml ;

la recette 16.14, Crer un nouveau rpertoire et y aller avec une seule commande, page
398.

RCS
En son temps, RCS tait rvolutionnaire. Il a servi de base CVS.

Avantage

cest toujours mieux que rien.

Inconvnients

les accs concurrents au mme fichier sont interdits ;

le concept de dpt central nexiste pas, mme si vous pouvez en crer un laide de
liens symboliques ;

le concept de dpt distant nexiste pas ;

le suivi des modifications ne concerne que les fichiers et il est impossible de stocker
ou de prendre en compte les rpertoires ;

la prise en charge des fichiers binaires est pauvre, tout comme celle des autres
objets tels que les liens symboliques. Contrairement CVS et SVN, qui sont constitus dun seul binaire principal pour lutilisateur, RCS est compos dun ensemble
de fichiers excutables.

Exemple
Crez un nouveau dpt pour votre propre utilisation dans votre rpertoire personnel :
/home/jp$ mkdir -m 0754 bin

Crez des scripts :


/home/jp$ cd bin
/tmp/scripts/bin$ cat << EOF > bonjour
> #!/bin/sh
> echo 'Bonjour tout le monde !'
> EOF
/home/jp/bin$ ci bonjour
bonjour,v <-- bonjour

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

RCS

589

enter description, terminated with single '.' or end of file:


NOTE: This is NOT the log message!
>> L'indispensable "Bonjour tout le monde".
>> .
initial revision: 1.1
done
/home/jp/bin$ ls -l
total 4.0K
-r--r--r-- 1 jp jp 258 Jul 20 02:25 bonjour,v

Que sest-il donc pass ? Lorsquun rpertoire nomm RCS nexiste pas, le rpertoire de
travail est utilis pour le fichier RCS. Si les options -u ou -l ne sont pas employes, le
fichier est enregistr, puis supprim. -l provoque le retour du fichier et son verrouillage
afin que vous puissiez le modifier, tandis que -u correspond au dverrouillage (autrement dit, en lecture seule). Essayez ces options. Tout dabord, rcuprons notre fichier,
puis crons un rpertoire RCS et recommenons lenregistrement.
/home/jp/bin$ co -u bonjour
bonjour,v --> bonjour
revision 1.1 (unlocked)
done
/home/jp/bin$ ls -l
total 8.0K
-r--r--r-- 1 jp jp 41 Jul 20 02:29 bonjour
-r--r--r-- 1 jp jp 258 Jul 20 02:25 bonjour,v
/home/jp/bin$ rm bonjour,v
rm: dtruire un fichier protg en criture fichier rgulier `bonjour,v'? o
/home/jp/bin$ mkdir -m 0755 RCS
/home/jp/bin$ ci -u bonjour
RCS/bonjour,v <-- bonjour
enter description, terminated with single '.' or end of file:
NOTE: This is NOT the log message!
>> L'indispensable "Bonjour tout le monde".
>> .
initial revision: 1.1
done
/home/jp/bin$ ls -l
total 8.0K
drwxr-xr-x 2 jp jp 4.0K Jul 20 02:31 RCS/
-r--r--r-- 1 jp jp 41 Jul 20 02:29 bonjour
/home/jp/bin$ ls -l RCS
total 4.0K
-r--r--r-- 1 jp jp 258 Jul 20 02:31 bonjour,v

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

590

Annexe D Gestion de versions

Vous remarquerez que le fichier originel est prsent en lecture seule. Cela nous permet de ne pas oublier de lextraire avec co -l avant de pouvoir le manipuler :
/home/jp/bin$ co -l bonjour
RCS/bonjour,v --> bonjour
revision 1.1 (locked)
done
/home/jp/bin$ ls -l
total 8.0K
drwxr-xr-x 2 jp jp 4.0K Jul 20 02:39 RCS/
-rw-r--r-- 1 jp jp 41 Jul 20 02:39 bonjour
/home/jp/bin$ echo "Salut M'man..." >> bonjour

Validez les changements, mais conservez la copie verrouille pour sa modification :


/home/jp/bin$ ci -l bonjour
RCS/bonjour,v <-- bonjour
new revision: 1.2; previous revision: 1.1
enter log message, terminated with single '.' or end of file:
>> * bonjour a t corrig.
>> .
done
/home/jp/bin$ ls -l
total 8.0K
drwxr-xr-x 2 jp jp 4.0K Jul 20 02:44 RCS/
-rw-r--r-- 1 jp jp 56 Jul 20 02:39 bonjour

Apportez une autre modification, puis vrifiez la diffrence :


/home/jp/bin$ vi bonjour
/home/jp/bin$ rcsdiff bonjour
===================================================================
RCS file: RCS/bonjour,v
retrieving revision 1.2
diff -r1.2 bonjour
3c3
< Salut M'man...
--> echo "Salut M'man..."

Validez les changements et conservez une copie non verrouille pour son utilisation
relle :
/home/jp/bin$ ci -u -m"* correction de l'erreur de syntaxe." bonjour
RCS/bonjour,v <-- bonjour
new revision: 1.3; previous revision: 1.2
done
/home/jp/bin$ ls -l
total 8.0K

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

RCS
drwxr-xr-x
-r--r--r--

591
2 jp jp 4.0K Jul 20 02:46 RCS/
1 jp jp 63 Jul 20 02:45 bonjour

Consultez lhistorique du fichier :


/home/jp/bin$ rlog bonjour
RCS file: RCS/bonjour,v
Working file: bonjour
head: 1.3
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 3;
selected revisions: 3
description:
L'indispensable "Bonjour tout le monde".
---------------------------revision 1.3
date: 2006/07/20 06:46:30; author: jp; state: Exp; lines: +1 -1
* correction de l'erreur de syntaxe.
---------------------------revision 1.2
date: 2006/07/20 06:43:54; author: jp; state: Exp; lines: +1 -0
* bonjour a t corrig.
---------------------------revision 1.1
date: 2006/07/20 06:31:06; author: jp; state: Exp;
L'indispensable "Bonjour tout le monde".
===========================================================================
==

Ajoutez des informations de version et demandez au systme de les actualiser. Validezles et examinez les modifications :
/home/jp/bin$ co -l bonjour
RCS/bonjour,v --> bonjour
revision 1.3 (locked)
done
/home/jp/bin$ vi bonjour
/home/jp/bin$ cat bonjour
#!/bin/sh
# $Id$
echo 'Bonjour tout le monde !'
echo "Salut M'man..."
/home/jp/bin$ ci -u -m'mot-cl ID ajout.' bonjour
RCS/bonjour,v <-- bonjour
new revision: 1.4; previous revision: 1.3
done
[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

592

Annexe D Gestion de versions

/home/jp/bin$ cat bonjour


#!/bin/sh
# $Id: bonjour,v 1.4 2006/07/20 06:48:30 jp Exp $
echo 'Bonjour tout le monde !'
echo "Salut M'man..."

Comparez la version actuelle la version r1.2, revenez cette ancienne version (invalide), ralisez votre erreur et revenez la version la plus rcente :
/home/jp/bin$ rcsdiff -r1.2 bonjour
===================================================================
RCS file: RCS/bonjour,v
retrieving revision 1.2
diff -r1.2 bonjour
1a2
> # $Id: bonjour,v 1.4 2006/07/20 06:48:30 jp Exp $
3c4
< Salut M'man...
--> echo "Salut M'man..."
/home/jp/bin$ co -r bonjour
RCS/bonjour,v --> bonjour
revision 1.4
done
/home/jp/bin$ cat bonjour
#!/bin/sh
# $Id: bonjour,v 1.4 2006/07/20 06:48:30 jp Exp $
echo 'Bonjour tout le monde !'
echo "Salut M'man..."

Script dutilisation
Voici un script qui peut faciliter lutilisation de RCS. Pour cela, il cre un dpt RCS
et automatise une grande partie du processus denregistrement et dextraction des fichiers sur lesquels vous souhaitez travailler. Nous vous conseillons dutiliser Subversion
ou CVS, mais, si ce nest pas possible, vous trouverez une certaine utilit ce script.
#!/usr/bin/env bash
# bash Le livre de recettes : travailler_sur
# travailler_sur - Travailler sur un fichier dans RCS.
# Dfinir un chemin sr et l'exporter.
PATH=/usr/local/bin:/bin:/usr/bin
export PATH
VERSION='$Version: 1.4 $' # JP Vossen
COPYRIGHT='Copyright 2004-2006 JP Vossen (http://www.jpsdomain.org/)'
LICENSE='GNU GENERAL PUBLIC LICENSE'

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

RCS

593

CAT='/bin/cat'
if [ "$1" = "-h" -o "$1" = "--help" -o -z "$1" ]; then
${CAT} <<-EoN
Usage : $0 {fichier}
Travailler sur un fichier dans RCS. Crer le sous-rpertoire
RCS, si ncessaire. Effectuer l'enregistrement initial, si
ncessaire, en demandant la saisie d'un message. Ce script
doit se trouver dans le mme rpertoire que le fichier.
EoN
exit 0
fi
# Utiliser un dpt pseudo-central.
REP_RACINE_RCS='/home/rcs'
# S'assurer que la variable $VISUAL est dfinie.
[ "$VISUAL" ] || VISUAL=vi
###################################################################
# Dbut du programme principal.
# S'assurer de l'existence du rpertoire racine de RCS.
if [ ! -d $REP_RACINE_RCS ]; then
echo "Cration de $REP_RACINE_RCS..."
mkdir -p $REP_RACINE_RCS
fi
# Vrifier qu'il n'y a pas de rpertoire RCS local.
if [ -d RCS -a ! -L RCS ]; then
echo "Un rpertoire 'RCS' local existe dj - arrt !"
exit 2
fi
# S'assurer que le rpertoire de destination existe.
if [ ! -d $REP_RACINE_RCS$PWD ]; then
echo "Cration de $REP_RACINE_RCS$PWD..."
mkdir -p $REP_RACINE_RCS$PWD
fi
# S'assurer que le lien existe.
if [ ! -L RCS ]; then
echo "Cration du lien RCS --> $REP_RACINE_RCS$PWD."
ln -s $REP_RACINE_RCS$PWD RCS
fi
if [ ! -f "RCS/$1,v" ]; then
# Si le fichier ne se trouve pas dj dans RCS,
# l'y ajouter avec la rvision v1.0.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

594

Annexe D Gestion de versions


echo 'Ajout de "Version initiale/par dfaut" du fichier dans RCS...'
# Lire le message.
echo -n 'Veuillez dcrire ce fichier : '
read msg_journal
# Enregistrer le fichier en v1.0.
ci -u1.0 -t-"$msg_journal" -m'Version initiale/par dfaut' $1

else
# Si le fichier se trouve dans RCS, travailler dessus.
# Extraire le fichier en mode verrouill afin de le modifi.
co -l $1
# Modifier le fichier en local.
$VISUAL $1
# Renregistrer le fichier, mais conserver une copie
# en lecture seule.
ci -u $1
fi

Voir aussi

man ci ;

man co ;

man ident ;

man merge ;

man rcs ;

man rcsclean ;

man rcsdiff ;

man rcsmerge ;

man rlog ;

man rcsfreeze ;

le chapitre 3 du livre Applying RCS and SCCS de Tan Bronson et Don Bolinger
(OReilly Media) ;

BSD Tricks: Introductory Revision Control , http://www.onlamp.com/lpt/a/428.

Autres outils
Enfin, vous devez savoir que certains logiciels de traitement de texte, comme OpenOffice Writer et Microsoft Word, disposent de trois fonctionnalits associes la gestion
des versions : comparaison de documents, suivi des modifications et versions.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Autres outils

595

Comparaison de documents
Cette fonctionnalit vous permet de comparer des documents dans leur format de fichier natif, que des outils comme diff ont des difficults prendre en charge. Vous pouvez lutiliser lorsque vous disposez de deux copies dun document pour lesquelles le
suivi des modifications na pas t activ ou lorsque vous devez intgrer les commentaires de diffrentes sources.
Mme sil est facile dextraire le fichier content.xml dun document OpenDoc, son contenu ninclut aucun saut de ligne et nest pas trs prsentable ni lisible. La recette 12.5, page
254, propose un script bash de comparaison qui tient compte de ce problme.
Le tableau D-1 vous indique comment accder la fonction de comparaison graphique
intgre, qui est beaucoup plus simple demploi quune procdure manuelle.

Suivi des modifications et versions


La fonction de suivi des modifications enregistre des informations concernant les changements apports un document. Le mode de rvision affiche de nombreuses balises
lcran pour prsenter lauteur, le contenu et la date des modifications. Cela savre bien
videmment utile pour toute forme de cration ou de modification, mais noubliez pas
de lire nos avertissements ci-aprs.
La gestion des versions permet denregistrer plusieurs versions dun document dans un
mme fichier. Elle peut se rvler trs pratique, mme dans des utilisations inattendues.
Par exemple, nous avons vu des configurations de routeurs copies et colles depuis un
terminal dans diffrentes versions dun mme document, des fins darchivage et de
suivi des modifications.
Les fonctions de suivi des modifications et de versions font continuellement grossir votre document. En effet, les lments modifis sont conservs et les lments supprims ne le sont pas rellement, mais seulement marqus comme tant supprims.
Si vous les activez par mgarde, elles peuvent constituer des fuites
dinformations trs dangereuses ! Par exemple, si vous envoyez des propositions similaires diffrentes socits concurrentes, aprs avoir
effectu une recherche/remplacement ou dautres modifications, toutes les entreprises peuvent savoir prcisment ce que vous avez chang
et quand vous lavez fait. Les versions les plus rcentes de ces outils proposent diverses mthodes qui essaient de vous avertir ou effacent les
informations prives avant quun document soit converti au format
PDF ou envoy par courrier lectronique.
Examinez les documents envoys comme pices jointes aux courriers
lectroniques, en particulier ceux provenant des fournisseurs. Vous
pourriez tre surpris !

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

596

Annexe D Gestion de versions

Accder ces fonctionnalits


Tableau D-1. Fonctions des logiciels de traitement de texte
Fonctionnalit

Writer

Comparaison de
documents

diterComparer le document OutilsComparaison et fusion


de documents

Suivi des modifications

diterModifications

OutilsSuivi des modifications

Versions

FichierVersions

FichierVersions

[05/03/08]

bash Le livre de recettes

Word

Elodie FRITSCH <elodie.fritsch@total.com>

E
Compiler bash

Dans cette annexe, nous allons vous montrer comment obtenir la dernire version de
bash et linstaller sur votre systme partir des fichiers sources. Nous verrons galement
les problmes que vous pourriez rencontrer tout au long de ce processus. Nous vous indiquerons comment signaler des bogues la personne responsable de bash. Ce contenu
apparat galement dans le livre Le shell bash, 3e dition de Cameron Newham et Bill Rosenblatt (ditions OReilly).

Obtenir bash
Si vous disposez dune connexion directe Internet, vous ne devriez pas avoir trop de
problmes obtenir bash ; sinon, le travail sera un peu plus important. La page daccueil
de bash se trouve ladresse http://www.gnu.org/software/bash/bash.html. Elle donne tous
les derniers dtails sur la distribution actuelle et comment la rcuprer.
Vous pouvez galement obtenir bash sur CD-ROM en le commandant directement
auprs de la Free Software Foundation, soit via la page web de commande (http://order.
fsf.org), soit en contactant la FSF :
The Free Software Foundation (FSF)
51 Franklin Street, 5th Floor
Boston, MA 02110-1301 USA
Tlphone : +1-617-542-5942
Tlcopie : +1-617-542-2652
Courriel : order@fsf.org

Extraire le contenu de larchive


Aprs avoir obtenu le fichier darchive par lune des mthodes prcdentes, vous devez
en extraire le contenu et linstaller sur votre systme. Lextraction peut se faire nimporte
o ; nous supposerons que vous avez extrait le contenu dans votre rpertoire personnel.
Pour pouvoir installer bash sur votre systme, vous devez disposer des privilges de root.
Si vous ntes pas administrateur systme disposant de cet accs, vous pouvez tout de
mme compiler et utiliser bash ; il vous sera simplement impossible de linstaller pour
[05/03/08]
Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

598

Annexe E Compiler bash

la globalit du systme. La premire chose faire est de dcompresser le fichier darchive en entrant gunzip bash-3.2.tar.gz. Ensuite, vous devez extraire le contenu de larchive en entrant tar -xf bash-3.2.tar. Les options -xf signifient extraire le contenu
archiv dans le fichier indiqu . Cette opration cre un rpertoire nomm bash-3.2
dans votre rpertoire daccueil. Si vous navez pas loutil gunzip, vous pouvez le rcuprer de la mme manire que vous avez obtenu bash ou utiliser simplement gzip -d.
Larchive contient tout le code source ncessaire compiler bash, une documentation
fournie et de nombreux exemples. Dans la suite de ce chapitre, nous examinerons tout
cela et comment obtenir un excutable de bash.

Contenu de larchive
Larchive de bash contient un rpertoire principal (bash-3.2 pour la version actuelle) et
un ensemble de fichiers et de sous-rpertoires. Voici les premiers fichiers examiner :
CHANGES
La liste complte des corrections de bogues et des nouvelles fonctionnalits introduites depuis la version pcdente.
COPYING
Le GNU Copyleft pour bash.
MANIFEST
La liste de tous les fichiers et rpertoires prsents dans larchive.
NEWS
La liste des nouvelles fonctionnalits depuis la version prcdente.
README
Une courte introduction et les instructions de compilation de bash.
Vous devez galement connatre lexistence de deux rpertoires :
doc
Les informations concernant bash, dans diffrents formats.
examples
Des exemples de fichiers de dmarrage, de scripts et de fonctions.
Les autres fichiers et rpertoires de larchive sont utiliss pendant la compilation. Sauf
si vous vous intressez au fonctionnement interne du shell, ils ne vous concernent pas.

Documentation
Le rpertoire doc contient quelques articles qui valent la peine dtre lus. De mme,
vous pouvez imprimer la page de manuel de bash afin de pouvoir lutiliser conjointement ce livre. Le fichier README rsume brivement les fichiers.
Le document le plus souvent utilis est la page de manuel (bash.1). Le fichier est au format troff celui des pages de manuel. Vous pouvez le lire en le passant au logiciel de
mise en forme de texte nroff et en dirigeant la sortie vers un utilitaire daffichage
pagin : nroff -man bash.1 | more devrait faire laffaire. Vous pouvez galement limpri-

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Contenu de larchive

599

mer en redirigeant la sortie vers limprimante (lp). Ce document rsume toute les fonctionnalits de votre version de bash et constitue la rfrence la plus jour disponible. Il
est galement accessible via lutilitaire man, une fois le paquetage install. Cependant, il
est parfois agrable den avoir une copie papier afin dy transcrire des notes.
Parmi les autres documents, FAQ contient les questions les plus frquemment poses,
avec les rponses, readline.3 est la page de manuel de readline et article.ms est un article
concernant le shell, publi dans le Linux Journal et crit par Chet Ramey, la personne actuellement responsable de la maintenance de bash.

Configurer et compiler bash


La compilation de bash sans autre intervention est facile. Il suffit de saisir ./configure,
puis make ! Le script configure dtermine si vous disposez des diffrents utilitaires et des
fonctions de la bibliothque C, ainsi que leur emplacement sur votre systme. Il stocke
ensuite les informations adquates dans le fichier config.h. Il cre galement un fichier
nomm config.status. Il sagit dun script que vous pouvez excuter pour recrer les informations de configuration actuelle. Pendant son excution, configure affiche des informations sur ce quil recherche et o il les trouve.
Le script configure fixe galement lemplacement dinstallation de bash ; par dfaut, il
sagit de /usr/local (/usr/local/bin pour lexcutable, /usr/local/man pour les pages de manuel, etc.). Si vous ne disposez pas des privilges du super-utilisateur et souhaitez le placer dans votre rpertoire daccueil ou si vous souhaitez installer bash dans tout autre
emplacement, vous devez indiquer le chemin configure. Pour cela, utilisez loption
--exec-prefix. Par exemple :
$ configure --exec-prefix=/usr

stipule que les fichiers de bash seront placs sous le rpertoire /usr. Notez que configure
prfre que les arguments des options soient donns avec un symbole gal (=).
Une fois la configuration termine et aprs avoir entr make, lexcutable de bash est
compil. Un script nomm bashbug est galement gnr. Il vous permet denvoyer des
rapports de bogues au format souhait par la personne charge de la maintenance de
bash. Nous verrons comment lutiliser plus loin dans cette annexe.
Une fois la compilation termine, vous pouvez voir si lexcutable de bash fonctionne
en entrant ./bash.
Pour installer bash, entrez make install. Tous les rpertoires ncessaires (bin, info, man et
ses sous-rpertoires) seront crs et les fichiers y seront copis.
Si vous avez install bash dans votre rpertoire personnel, noubliez pas dajouter votre
propre chemin bin PATH et votre propre chemin man MANPATH.
bash est prconfigur avec pratiquement toutes ses fonctionnalits actives. Il est possible de personnaliser votre version en indiquant ce que vous souhaitez avec les options
--enable fonctionnalit et --disable fonctionnalit de la ligne de commande de
configure. Le tableau E-1 donne la liste des fonctionnalits configurables et une courte
description de leur rle.
Les options disabled-builtins et xpg-echo-default sont dsactives par dfaut. Les
autres sont actives.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

600

Annexe E Compiler bash

Tableau E-1. Fonctionnalits configurables de bash


Fonctionnalit

Description

alias

Prise en charge des alias.

arith-for-command

Prise en charge de lautre forme de la commande for qui se


comporte comme linstruction for du langage C.

array-variables

Prise en charge des tableaux une dimension.

bang-history

Expansion et modification de lhistorique comme dans le shell


C.

brace-expansion

Dveloppement des accolades.

command-timing

Prise en charge de la commande time.

cond-command

Prise en charge de la commande conditionnelle [[.

cond-regexp

Prise en charge de la correspondance des expressions rgulires


POSIX en utilisant loprateur binaire =~ dans la commande
conditionnelle [[.

directory-stack

Prise en charge des commandes pushd, popd et dirs pour la


manipulation des rpertoires.

disabled-builtins

Activation de lexcution dune commande interne avec la


commande builtin, mme dans le cas o elle a t dsactive
par enable -n.

dparen-arithmetic

Prise en charge de ((...)).

help-builtin

Prise en charge de la commande interne help.

history

Historique via les commandes fc et history.

job-control

Contrle des tches laide de fg, bg et jobs si le systme


dexploitation le permet.

multibyte

Prise en charge des caractres multioctets si le systme


dexploitation le permet.

net-redirections

Gestion spciale des noms de fichiers de la forme


/dev/tcp/HTE/PORT et /dev/udp/HTE/PORT lorsquils sont
employs dans les redirections.

process-substitution

Activation de la substitution de processus si elle est accepte


par le systme dexploitation.

prompt-string-decoding Activation de lchappement des caractres dans PS1, PS2, PS3


et PS4.
progcomp

Fonctionnalits de compltion programmable. Si readline nest


pas active, cette option na aucun effet.

readline

Fonctionnalits ddition et dhistorique readline.

restricted

Prise en charge du shell restreint, de loption -r du shell et de


rbash.

select

La construction select.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Contenu de larchive

601

Tableau E-1. Fonctionnalits configurables de bash (suite)


Fonctionnalit

Description

usg-echo-default
xpg-echo-default

Par dfaut, echo dveloppe les caractres avec chappement


sans ncessiter loption -e. La valeur par dfaut de loption
xpg_echo du shell est fixe on. La commande echo de bash se
comporte plus comme la version dcrite dans Single Unix Specification, Version 2.

De nombreuses autres fonctionnalits du shell peuvent tre actives ou dsactives en


modifiant le fichier config-top.h. Pour plus de dtails sur ce fichier et la configuration de
bash en gnral, consultez le document INSTALL.
Enfin, pour nettoyer le rpertoire source et supprimer tous les fichiers objets et les excutables, entrez make clean. Assurez-vous davoir dabord excut make install. Sinon,
vous devrez recommencer linstallation depuis le dbut.

Tester bash
Toute une batterie de tests peut tre lance sur une version de bash nouvellement compile, afin de vrifier quelle fonctionne correctement. Ces tests sont des scripts drivs
de problmes signals dans les versions prcdentes du shell. En les excutant sur la dernire version de bash, aucune erreur ne doit se produire.
Pour dmarrer les tests, saisissez simplement make tests dans le rpertoire principal de
bash. Le nom de chaque test est affich, avec des messages davertissement, puis il est lanc. Lorsque les tests sexcutent correctement, aucune sortie nest produite (except lorsque les messages davertissement signalent le contraire).
Si lun des tests choue, vous obtenez une liste des diffrences entre les rsultats attendus et les rsultats obtenus. Si cela se produit, vous pouvez remplir un rapport de bogue
et lenvoyer la maintenance de bash. Consultez la section Signaler des bogues, page 602,
pour savoir comment procder.

Problmes potentiels
Mme si bash a t install sur un grand nombre de machines et de systmes dexploitation diffrents, des problmes surviennent parfois. En gnral, ils ne sont pas trop srieux et, le plus souvent, une petite investigation conduit rapidement une solution.
Si bash ne se compile pas, vous devez commencer par vrifier que configure a bien dtermin votre machine et votre systme dexploitation. Ensuite, consultez le fichier NOTES
qui contient des informations sur des systmes Unix particuliers. Lisez galement le fichier INSTALL qui donne des informations supplmentaires sur la manire de passer
configure les instructions de compilation spcifiques.

Installer bash en shell de connexion


Voir la recette 1.9, page 16.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

602

Annexe E Compiler bash

Exemples
Voir lannexe B, Exemples fournis avec bash, page 559, pour une description des exemples.

Aide
Quelle que soit la qualit dun produit ou le niveau de documentation quil fournit,
vous pouvez vous trouver dans une situation o quelque chose ne fonctionne pas ou
que vous ne comprenez pas. Lorsque cest le cas, il faut soigneusement lire la documentation (en jargon informatique : RTFM1). Le plus souvent, cela rpondra votre question
ou indiquera vos erreurs.
Parfois, cette lecture ne fera quajouter votre confusion ou confirmera que le logiciel
a un problme. Dans ce cas, vous devez commencer par parler votre expert bash local
afin quil tudie le problme. Si cela ne donne rien, ou si vous ne connaissez aucun expert, vous devez utiliser dautres moyens (aujourdhui, uniquement par Internet).

Poser des questions


Si vous avez des questions propos de bash, il existe aujourdhui deux manires dobtenir une rponse. Vous pouvez les envoyer par courrier lectronique bash-maintainers@gnu.org ou la poster dans les groupes USENET gnu.bash.bug.
Dans les deux cas, soit la personne charge de la maintenance de bash, soit un expert
prsent sur USENET, vous prodiguera un conseil. Lorsque vous posez une question, essayez den donner un bon rsum dans la ligne dobjet (voir http://www.linuxfrance.org/article/these/smart-questions/smart-questions-fr.html).

Signaler des bogues


Les rapports de bogues doivent tre envoys bug-bash@gnu.org et inclure la version de
bash et du systme dexploitation sur lequel il sexcute, le compilateur employ pour
construire bash, une description du problme, une description de la manire dont le
problme a t cr et, si possible, un correctif du problme. Pour cela, la meilleure manire de procder consiste employer le script bashbug install avec bash.
Avant de lancer bashbug, vrifiez que la variable denvironnement EDITOR est fixe votre diteur favori et quelle a t exporte (bashbug utilise par dfaut Emacs, qui nest
peut-tre pas install sur votre systme). Lorsque vous excutez bashbug, il entre dans
lditeur avec un formulaire partiellement vide. Certaines informations (version de
bash, version du systme dexploitation, etc.) ont t remplies automatiquement. Nous
allons examiner rapidement ce formulaire, mais il est trs bien auto-document.
Le champ From: doit contenir votre adresse de courrier lectronique. Par exemple :
From: duchesse@merveilles.oreilly.fr

1. N.d.T : RTFM signifie Read The F(laming) Manual.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Aide

603

Puis vient le champ Subject:. Faites un effort pour le remplir car cela facilite le travail
des personnes charges de la maintenance lorsquelles examinent votre envoi. Remplacez simplement la ligne entoure de crochets par un rsum du problme.
Les lignes suivantes sont une description du systme et ne doivent pas tre modifies.
Dans le champ Description:, vous devez donner une description dtaille du problme et en quoi il diffre de ce que vous attendiez. Essayez dtre aussi prcis et concis que
possible dans cette description.
Le champ Repeat-By: explique comment vous avez gnr le problme. Si ncessaire,
donnez la liste exacte des squences de touches employes. Parfois, vous ne serez pas en
mesure de reproduire vous-mme le problme, mais vous devez quand mme remplir
ce champ en indiquant les vnements y conduisant. Essayez de rduire le problme
son minimum. Par exemple, sil sagit dun script shell long, essayez disoler la section
qui a produit le problme et nincluez quelle dans votre rapport.
Enfin, le champ Fix: est utilis pour proposer une solution de correction au problme
si vous lavez trouve. Si vous navez aucune ide des raisons du problme, laissez-le vide.
Si le responsable de la maintenance peut facilement reproduire et identifier le problme, il sera corrig trs rapidement. Vous devez donc
vrifier que a section Repeat-By (et, dans lidal, Fix) est aussi complte que possible. Nous vous conseillons galement de lire
http://www.linux-france.org/article/these/smart-questions/smart-questionsfr.html.

Lorsque vous avez fini de remplir le formulaire, enregistrez-le et quittez votre diteur.
Il sera automatiquement envoy la maintenance.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Index

Symboles
.[!.]* 11
^ (accent circonflexe) 11, 158
{} (accolades) 44, 92, 96
bloc de code 355
(apostrophes inverses) 49
voir aussi $()
@ (arobase) 9, 211
* (astrisque) 9, 11, 126, 157
correspondre un nombre quelconque de
caractres 126
** (astrisque double ) 114
/ (barre oblique) 38, 110
avec -F 9
\ (barre oblique inverse) 157, 158
au dbut 297
\; (barre oblique inverse et point-virgule) 200
| (barre verticale) 46
(apostrophe) 13, 33, 157, 263, 572
tube 46, 569
|| (barre verticale double) 81
{}, contient des noms pendant lexcution dune
commande 200
[ (crochet) 11
[[]] (crochets doubles) 126
[] (crochets simples) 11, 131, 157, 158
: (deux-points) 72
:= (deux-points et signe gal) 107
# (dise) 4, 87
$ (dollar) 32, 86, 114, 158
en fin 4
${#} (dollar, accolade, dise et accolade) 101, 257
$$ (dollar double) 253
$@ (dollar et arobase) 99

[05/03/08]

bash Le livre de recettes

$* (dollar et astrisque) 96
$() (dollar et parenthses) 49
voir aussi " (guillemets)
$? (dollar et point dinterrogation) 78
& (esperluette) 76
&& (esperluette double) 76
&> (esperluette et suprieur ) 41
$(()), expression 113
. (fichier point) 11
< fichierEntree, omettre permet de rediriger la
sortie nimporte o 32
" (guillemets) 12, 33, 263, 572
$$ (identifiant de processus) 77
< (infrieur ) 59
<= (infrieur et signe gal) 250
$-, liste des options en cours du shell 16
- (moins), oprations 310
:-, oprateur daffectation 106
:+, oprateur de variable 211
= (ou ==), comparer des chanes 124
() (parenthses) 45, 197
(()) (parenthses doubles) 132
+ (plus) 43
oprations 310
. (point) 72, 157, 209
! (point dexclamation) 11
!! (point dexclamation double) 155, 478
!$ (point dexclamation et dollar) 481
? (point dinterrogation) 11, 126
correspondre un seul caractre 126
oprateur de correspondance de motifs du
shell 11, 546
.* (point et astrisque) 11, 157
./ (point et barre oblique) 73
accder au rpertoire de travail 7

Elodie FRITSCH <elodie.fritsch@total.com>

606
; (point-virgule) 76, 117
% (pourcent), dfinir des formats 34
= (signe gal) 86, 114
== (signe gal double) 250
> (suprieur ) 36, 38, 50, 59
oprateur de redirection 208
>> (suprieur double) 41, 120
>& (suprieur et esperluette) 41
${:-}, syntaxe 104
${:=}, syntaxe 106
${:?}, syntaxe 108
<<-, syntaxe 63
~ (tilde) 4, 108
- (tiret) 43, 408
#!, trouver bash 334
, (virgule), oprateur 115

Nombres
$0, variable 245
0m, effacer tous les attributs et supprimer les
couleurs 375
-1, option 9
${1:0:1}, syntaxe 257

A
<a>, balises 262
-a, oprateur 120
-a, option
ls, commande 9
type, commande 6
-A, option (mkisofs) 253
absolus, chemins 38
figer 295
accder des donnes distantes 320
accent circonflexe (^) 11, 158
accolades ({}) 44, 92, 96
bloc de code 355
expansion 571
adresse IP 349351
affectation, oprateurs 114
afficher
des photos dans un navigateur 242
la sortie en hexadcimal 346
les chanes de compltion 408
une variable pour sa modification 378
AFFICHER_ERREUR, fonction 245
afficheurs de documents 432
agent de transfert du courrier 360
AIDE 293
aide abrge, usage 402
AIX 23
ajouter
des donnes au dbut 449, 452
des rpertoires 377
Ajout/Suppression dapplications 20

[05/03/08]

bash Le livre de recettes

Index
albums photo 242246
algorithmes de compression 179
alias 221
(apostrophe) avec 220
effacer 296
viter 221
expand_aliases 386
expansion, supprimer avec une barre
oblique inverse (\) au dbut 297
Host_Alias 318
malveillants 296
rcursifs 571
rdfinir des commandes 219
traitement sur la ligne de commande 571
\unalias -a, commande 296
User_Alias 318
analyse
${#}, pour lanalyse directe 257
arguments 240, 257
de la ligne de commande 139
avec read dans un tableau 267
convertir la sortie en tableau 264
fichier CSV 288
HTML 262
noms de rpertoires 182
sortie dun appel de fonction 265
texte, avec une instruction read 266
un caractre la fois 269
annes bissextiles 234, 235
ANSI, squences dchappement 374
pour la couleur 508
apostrophe (), protection 220
AppArmor 317
applications, rpertoires de 377
apostrophes inverses () 49
voir aussi $()
apropos, chercher des expressions dans les pages
de manuel 7
apt-get, commande 20
arborescence
de fichiers 38
source 270
architecture x86 339
archives 23, 309, 405
compresses, extraire 407
crer 439
extraire 182
ARG_MAX 358
arguments
${}, syntaxe pour les variables 110
analyser 139, 240, 257
apostrophes autour des noms de fichiers 430
cd, commande 383
compter 101
dcomposer 357

Elodie FRITSCH <elodie.fritsch@total.com>

Index

607

arguments (suite)
doption 103
getopts 258261
insuffisants 109
liste trop longue, erreur 357
options avec 258
parcourir 96
positionnels 106
rels 103
rpter sans resaisir 482
rutiliser 480
-v, option 104
$VERBEUX 104
arithmtique
** (astrisque double), lever la
puissance 114
$ (dollar) 114
$(()), expression 113
= (signe gal) 114
boucles
for 470
while 131
dates et heures 233
espaces 114
expansion 108
expression
entire 113
valuer 571
let, instruction 113
oprateurs 114
daffectation 114
virgule (,) 115
arobase (@) 9, 211
article.ms, article bash 27
assaillant non-root 305
astrisque (*) 126, 157
$* (dollar et astrisque) 96
correspondre un nombre quelconque de
caractres 126
dans les chanes 11
indiquer la rptition de zro occurrence ou
plus 157
signalant un fichier excutable 9
astrisque double (**), lever la puissance 114
attaque de lhomme du milieu 328
Aucun fichier ou rpertoire de ce type,
erreur 486
automatiser un processus 363365
autorisations 310
stocker les informations 7
awk
commande 274
dcouper en prsence despaces
multiples 274
programme 160, 162

[05/03/08]

bash Le livre de recettes

B
barre oblique (/) 38, 110
barre oblique inverse (\) 13, 157, 158
barre oblique inverse et point-virgule (\;) 200
barre verticale (|)
(apostrophe) 33, 572
tube 46, 569
Barrett, Daniel 321, 329
base de donnes, configurer avec MySQL 271
basename, commande 141
bash
archives 309
bash --version, vrifier linstallation de
bash 16
code source 27
documentation 26
fonctions 211
$IFS (Internal Field Separator) 267
instructions dinstallation 27
invoquer 505
partager entre des sessions 435
Ramsy, Chet 22, 27
redirecteur 41
reproduire lenvironnement 414
umask, commande interne 299
version 3.0, correspondance de motifs 128
version 3.1+, changer la sensibilit la
casse 129
.bash.0 28
bash.1, page de manuel 28
bashbug.0, page de manuel 28
bashbug.1, page de manuel 28
bash-completion, liste des modules de la
bibliothque 406
bashgetopt.h 403
~/.bash_history 412
~/.bash_login 411
~/.bash_logout 412
~/.bash_profile 411
bash_profile, exemple de 417
~/.bashrc 411
bashrc, exemple de 419
bashref, Bash Reference Guide 28
bashref.info, manuel de rfrence par
makeinfo 28
bashref.texi, manuel de rfrence 28
bashtop 27
bdiff 458
Beagle, moteur de recherche 201
Beebe, Nelson H.F. 292
BEGIN, mot-cl (awk) 164
bennes bits 153
bg, reprendre une tche 77
bibliothques tierces parties 406

Elodie FRITSCH <elodie.fritsch@total.com>

608

Index

~/bin, rpertoire 389


bin, rpertoire 73
/bin/bash 386
bind, commandes 387
#!/bin/sh 334
blocs 199
de donnes modifies 446
boucles 135
for 470
while 131
branches multiples 137
Browser Appliance v1.0.0 339
BSD 21, 338
bzip2, compression de fichier 178

C
-c, option (grep) 151
\c, pour les squences dchappement decho 35
cachs, fichiers point 10
capturer les signaux 215, 215219
caractres 187
analyser un par un 269
astrisque (*), correspondre un nombre
quelconque de 126
barre oblique inverse (\), correspondre des
caractres spciaux 158
classe de, inverser
avec un accent circonflexe (^) 11
avec un point dexclamation (!) 11
compter 187
correspondance de motifs 546
-d, option
(cut), prciser des dlimiteurs 185
(tr), pour supprimer 185
de dbut autres quune tabulation 64
dise (#) 87
espaces 97, 346
tranges dans les noms de fichiers 193
gnriques 10, 503
motifs pour les correspondances 157
non imprimables 346
incorpors 370
par dfaut pour le papier et lcran 91
point dinterrogation (?), correspondre un
seul caractre 126
remplacer 183
spciaux pour renommer ou supprimer des
fichiers 448
tabulation 64, 177, 281
case, instruction 137, 241, 259, 363
identifier des options 257
casse, sensibilit 138
cat, commande 37, 76, 246, 253
cd, commande 45, 78, 222, 383
crer une meilleure 396, ??397

[05/03/08]

bash Le livre de recettes

CD, graver 251


cdAnnotation 253
cdrecord 251
CentOS 20, 176
chanes
* (astrisque) 126
motif de fichier 11
[ (crochet) 11
[[]] (crochets doubles) 126
[] (crochets simples) dans 11
$-, liste des options en cours du shell 16
= (ou ==), comparer des chanes 124
? (point dinterrogation) 11
correspondre un seul caractre 126
alignes gauche 34
analyser les caractres un par un 269
caractristiques, tester 123
compter 164
constantes, utiliser pour les valeurs par
dfaut 107
correspondance de motifs 126
de compltion, afficher 408
deuxime chiffre 34
espaces incorpores 34
-f, option (awk), compter des valeurs 165
guillemets 124
dans les arguments 34
NF, variable (awk), boucler sur des
chanes 165
nulles 358
oprateurs de manipulation 111
-p, option (read), afficher une invite 65, 69
${paramtre/motif/chane} 503
premiers chiffres 34
$PS2, invite secondaire 390
rechercher toutes les occurrences 150
recherches insensibles la casse 154
renommer des fichiers 109
shopt -s nullglob, dvelopper les fichiers en
chanes nulles 358
signe moins 34
sortie, variantes 150
sous-chane, fonction 269
tableaux associatifs (hachages en awk) 165
taille maximum, modificateurs 34
taille minimum, modificateurs 34
test, commande interne 123
champs 176, 273, 276
dlimiteur 281
sparateur 263, 282
changer
de rpertoire 398
les noms des commandes 385
CHANGES, historique des modifications de
bash 27

Elodie FRITSCH <elodie.fritsch@total.com>

Index
chemins
absolus 38, 295
figer 377
changer dfinitivement 376
fixer explicitement 377
mises jour 376
modifier 382
relatifs 38
scurit 294
srs 294
cheval de Troie 293
chmod 310
choisir, fonction, invites et vrification dune
date de paquetage 66
chpass -s shell, changer de shell par dfaut 17
chroot
commande 316
prisons 316
rcupration du systme 316
chsh
-l, lister les shells valides 17
ouvrir un diteur 17
-s /bin/bash, faire de bash le shell par
dfaut 17
-s, changer de shell par dfaut 17
--clean (keychain), vider les cls SSH en
cache 326
clear
commande 438
utiliser avec des captures 428
cls
prives 321
publiques 323
*.pub, fichier 321
client de messagerie 362
cmdhist 395
Cmnd_Alias (sudo) 318
cmp 446
code
de sortie ($?) 78, 369, 378
excuter interactivement 15
source de bash 27
combines, commandes 119
comm, commande 459
Comma Separated Values (CSV) 287
command, commande 204, 337, 399
-p, option 337
command, mot-cl 222
commandes 73
affectes par la protection 572
apt-get 20
calculatrice en ligne 147
cat 37, 76, 246, 253
cd 45, 78, 222
utiliser 399

[05/03/08]

bash Le livre de recettes

609
chroot 316
code de sortie ($?) 74
combines 119
comm 459
command 204, 221, 337, 399
compgen 408, 409
compiler et diter les liens 405
complete 407
corriger une faute de frappe 478
crypt 320
cut 176, 273
date 223
diff 256
echo 32, 35, 74, 222, 342344
env 334
erreurs commande non trouve 212,
491, 502
eval 573
exec 356
excuter
en arrire-plan 77
plusieurs en squences 75
export 372
externes 14
fg 77
file 181
find 192
fmt 188
forces de SSH 329
getconf ARG_MAX 358
getline 164
grep 60, 149, 263
hash -r 297
head 42
history 393
if 378
info 431
kill 80, 408
less 47, 160, 189
ls 9
man 7
mmorises 297
mkdir 399
mv 110
mysql 272
nohup 80, 208
noms, changer ou raccourcir 385
numro 374
od 347
pause (DOS) 471
pr 188
redfinir avec des alias 219
rename 431
rpter 477
rm 49, 78

Elodie FRITSCH <elodie.fritsch@total.com>

610
commandes (suite)
sparer par des points-virgules 76
seq 136
set 94, 387, 505
shopt 387
sort 171, 173
source 202, 209
split 345
su 5, 456
substitution 108, 354
sudo 5, 17, 456
svn 133
tail 42
tar 178
tee 47, 52
test 118
tr 185
type 14, 221
\unalias -a 296
/usr/bin/env 334
utiliser sudo sur plusieurs 454
vrifier le succs 73, 77
vipw 17
wc 187
which 6, 14, 203
xargs 193, 357
commandes internes
bash, rediriger le rseau 359
BUILTIN_ENABLED 402
builtin_name 402
builtins.0, page de manuel 28
builtins.1, page de manuel 28
builtins.h 403
chargeables 401
charger 401
code C 401
compltion textuelle, tendre 407
dsactiver 14
description, structure 401
crire 401
enable 14
-a, afficher les commandes 14
-n, dsactiver avec 15
./examples/chargeables/ 401
help 15
ignorer des fonctions et des alias 221
mmoire et conservation lors du
chargement 405
nom_commande 402
popd 476
pushd 476
pwd 5
remplacer des commandes 14
shift 140, 259

[05/03/08]

bash Le livre de recettes

Index
test 123
tty 401
unmask 299
commentaires 87, 102, 321
comparaison, oprateurs 125
comparer le contenu de documents 254
COMPAT, problmes de compatibilit 27
compgen, commande 408, 409, 504
complete, commande 407, 504
compltion programmable 299, 406
$COMPREPLY 409
compter les mots 187
comptes
partags 314
root 4, 17, 70, 376
$COMP_WORDS, variable 409
concurrence critique 293, 305
config.h 403
configuration et personnalisation
0m, effacer tous les attributs et supprimer les
couleurs 375
alias 385
ANSI 374
archives 405
compresses, extraire 407
argument de cd 383
bash --help 368
bash -c help 368
bash -c "help set" 368
bash -x 368
bash-completion, liste des modules de la
bibliothque 406
bashgetopt.h 403
~/.bash_history, fichier denregistrement de
lhistorique des commandes 412
~/.bash_login, fichier de profil personnel des
shells de session Bourne 411
~/.bash_logout 412
bash_profile, exemple de 417
~/.bash_profile, fichier de profil personnel
des shells de session bash 411
bashrc, exemple de 419
~/.bashrc, fichier denvironnement
personnel des sous-shells bash 411
bibliothques tierces parties 406
~/bin, rpertoire 389
bind, commandes 387
BUILTIN_ENABLED 402
builtins.h 403
caractres non imprimables incorpors 370
cd, commande, amliorer 396
$CDPATH 383, 384
chanes de compltion, afficher 408
chanes dinvite 372

Elodie FRITSCH <elodie.fritsch@total.com>

Index
configuration et personnalisation (suite)
chemins 376, 377, 382
absolus, figer 377
clear, utiliser avec des captures 428
cmdhist 395
code
C 401
de sortie ($?) 369, 378
commandes
command 399
compgen 408, 409
complete 407
noms, changer ou raccourcir 385
numro 374
commandes internes 399
chargeables 401
chargeables, liste 401
crire 401
mmoire et conservation lors du
chargement 405
compltion programmable 406
amliorer avec des bibliothques 406
compltion textuelle intgre, tendre 407
$COMPREPLY 409
$COMP_WORDS 409
config.h 403
configurations, rpertoire 414
configure, script 405
$cour 409
Ctrl-X P, afficher $PATH 378
dbuter une configuration personnelle 416
description, structure pour les commandes
internes 401
_echec_de_mcd_ 399
echo, instruction, prudence
dutilisation 415
enable, commande interne 402
environnement bash, reproduire 414
erasedups 394
/etc/bash.bashrc (Debian), fichier
denvironnement global 411
/etc/bash_completion, pour la bibliothque
de compltion programmable 411
/etc/bashrc
fichier denvironnement global pour les
sous-shells (Red Hat) 411
pour les paramtres denvironnement
de niveau systme 417
/etc/inputrc, pour la configuration globale
de GNU Readline 411
/etc/profile
de niveau systme paramtres de
profil 417
fichier global denvironnement de
session pour shells Bourne 411

[05/03/08]

bash Le livre de recettes

611
./examples/chargeables/, commandes
internes prdfinies 401
EXECUTION_FAILURE 403
EXECUTION_SUCCESS 403
expand_aliases 386
export, commande 372
EX_USAGE 403
Fedora Core 5 368
fichiers
de configuration, utiliser dans les scripts
bash 210
den-tte C 403
rc douverture de session bash 412
RC (initialisation) 411, 414416
fonctions 385
grep -l PATH ~/.[^.]* 376
gunzip, utilitaire 407
hello.c 401
histappend 395
$HISTCONTROL 394
$HISTFILE 394
$HISTFILESIZE 394
$HISTIGNORE 394
historique
automatiser le partage 393
entre sessions et synchronisation 392
fixer les options 393
numro 374
history, commande 393
$HISTSIZE 394
$HISTTIMEFORMAT 394
if, commande 378
ignoreboth 394
ignoredups 394
ignorespace 394
$include 388
$INPUTRC 387
.inputrc 387
inputrc, exemple de 425
~/.inputrc, pour GNU Readline 412
internal_getopt 403
invites 368, 370, 374
secondaires 390
kill, commande 408
lancer_screen, exemple 426
liens symboliques 386
lithist 395
loptend 403
m (caractre), indiquer une squence
dchappement pour la couleur 375
macros pour la documentation du shell 377
Makefile 401
messages derreur, identifier 382
Meta Ctrl-V, afficher une variable pour sa
modification 378

Elodie FRITSCH <elodie.fritsch@total.com>

612

Index

configuration et personnalisation (suite)


mkdir, commande 399
mode POSIX 384
motif de egrep 378
niveaux de shells 369
nom dutilisateur@nom dhte 369
long 369
nom_commande 402
nom_fonction 402
noms des signaux 408
no_options(list) 403
NULL 403
objets partags dynamiques 405
options 368
de dmarrage 368
paramtres
de profil de niveau systme 417
denvironnement de niveau
systme 417
$PATH 377382
modifier de faon permanente 376
PATH="nouv_rp:$PATH" 377
PATH="$PATH:nouv_rp" 377
points au dbut des noms de fichiers 414
~/.profile, fichier de profil personnel pour les
shells de session Bourne 412
$PROMPT_COMMAND 374
promptvars 372
$PS1, invite de commande 368, 372
erreurs avec 428
$PS2, invite secondaire 368, 390
$PS3, invite de select 372, 390
$PS4, invite 392
PTY, numro de pseudo-terminal 369
$PWD, afficher le rpertoire de travail
complet 373
readline 377, 387
rpertoires
crer et y aller en une tape 398
dapplications 377
de travail 373
modifiables par tous, viter dans le
chemin de root 377
utiliser la commande find dans de
nombreux niveaux 399
reset_internal_getopt 403
root, chemins de 376, 377
-s, option (exemple de commande interne
chargeable) 401
select, instruction 390
squences dchappement ANSI 370
set +x 368
shell.h 403
_signaux 409
stdio.h 403

[05/03/08]

bash Le livre de recettes

strftime 394
_struct 402
tableau_aide 402
tches, nombre en cours de gestion 369
tlchargements pour ce livre 371
tty, commande interne 401
ttyname 403
unalias 385
usage, aide abrge 402
utilitaires personnels 389
\w, afficher le chemin complet 373
\W, afficher le nom de base 373
WORD_LIST 403
xterm 370
rempli de charabia 374
xtrace, invite de dbogage 372
configurations, rpertoire de 414
configure, script 405
construction conditionnelle 116
continue, instruction 168
contrles daccs obligatoires 317
convertir
date en secondes depuis lorigine 230
secondes depuis lorigine en dates et
heures 231
Conway, Damian 89
Copernic Desktop Search 201
correspondance de motifs
?, oprateur du shell 11, 546
astrisque (*), correspondre un nombre
quelconque de caractres 126
bash version 3.0 128
caractres 546
chanes contenant un astrisque (*), un
point dexclamation (!) ou un
crochet [ 11
chercher avec des motifs complexes 157
crochets doubles ([[]]), pour la
correspondance sur le ct droit de
loprateur gal 126
egrep 378
et expression rgulires 157
extglob, option pour la correspondance
tendue 127
globalisation (correspondance de motifs
tendue) 127
.jpeg 126
.jpg, option 126
${paramtre/motif/chane} 503
point dinterrogation (?), correspondre un
seul caractre 126
sensibilit la casse 127
recherches 154
symboles 503
regrouper 127

Elodie FRITSCH <elodie.fritsch@total.com>

Index
correspondance de motifs (suite)
tester des chanes avec 126
tri alphabtique de bash 493
*.txt 11
*txt 11
${variable/motif/remplacement} 202
ct
droit 287
gauche 287
$cour, variable 409
courrier lectronique, envoyer 360362
court-circuite, expression 122
couteau suisse de TCP/IP (Netcat) 359
CPIO, fichiers 180
crer des rpertoires 398
crochet ([), dans les chanes 11
crochets doubles ([[]]) 126
crochets simples ([]) 131, 158
dans les chanes 11
cron 361
divers 235
crypt, commande 320
CS_PATH 336
CSV (Comma Separated Values) 287, 288
Ctrl-A K, pour fermer la fentre et quitter la
session 436
Ctrl-X P, afficher $PATH 378
curl 350
cur_weekday 229
cut, commande 176, 273
Cygwin 24
cygwin1.dll 24

D
-d, option (date) 226, 228
date, commande 223
dates
de modification 120
de paquetage, vrifier 66
par dfaut 225
dates et heures
annes bissextiles 234, 235
arithmtique 233
commande Unix, omettre lanne 234
convertir en un jour et une date
spcifiques 230
cron 235
crontab 235
cur_weekday 229
-d, option 226, 228
date, commande 223
date, commande GNU 223, 226, 228, 231
dates par dfaut 225
demain 232
end_month 229

[05/03/08]

bash Le livre de recettes

613
fin de mois du mois indiqu 229
formats viter 225
fuseaux horaires 225, 234
gawk 223
getdate 227
horaires dt 235
ISO 8601, afficher des dates et des
heures 225
jour de la semaine pour le jour indiqu 229
JOURS, utiliser avec prudence 229
Linux Vixie Cron 235
mettre en forme une chane avec
strftime 544
nombre de jours entre deux dates 229
NTP (Network Time Protocol) 233
options de format 225
Perl 230, 231, 235
plages
de dates 227
de jours 236
pn_day 229
pn_day_nr 229
pn_month 229
pn_weekday 229
requte SQL 227
scripts, excuter le jour N 235
secondes 234, 235
depuis lorigine 230, 231, 234
Shell Corner: Date-Related Shell Functions
dans UnixReview 229
strftime(), fonction C (man 3 strftime),
options de format 225
this week, utiliser avec prudence 229
UnixReview 229
xme jour avant ou aprs celui indiqu 229
non rcursif 229
xme jour de la semaine avant ou aprs celui
indiqu 229
xme mois avant ou aprs celui indiqu 229
%z, format 225
De lart de programmer en Perl (ditions
OReilly) 89
.deb, fichiers 180
voir aussi .rpm
Debian 18, 180, 190, 204
dbogage et fichiers core 298
dbordement de tampons 293
DEBUG, signal 218
dbut, caractres de 64
declare, option 218
dcompresser des fichiers 256
dconnectes, sessions 433, 436
dlimiteurs 176, 177
de champs 281
demain, obtenir la date avec Perl 232

Elodie FRITSCH <elodie.fritsch@total.com>

614

Index

dmarrage, options de 368


dmon 207
dernier entr, premier sorti 476
dsactiver les commandes internes 14
description, structure pour les commandes
internes 401
deux-points (:), sparer des rpertoires 72
deux-points et signe gal (:=) 107
developerWorks (IBM) 326
devier, sortie du script 50
/dev/nul 153
dise (#) 4, 87
diff, commande 256, 441, 445, 457
diffrences
smantiques, avec des parenthses 45
syntaxiques, avec des parenthses 45
DIMINUER, fonction 250
distribution bureautique base sur KDE 339
documentation 26, 88, 377
pour lutilisateur 88
documents, comparer 254
dollar ($) 32, 86, 114, 158
substitution de variables 571
dollar, accolade, dise et accolade (${#}) 101, 257
dollar double ($$), variable 253
dollar et arobase ($@) 99
dollar et astrisque ($*) 96
dollar et parenthses ($()), pour la substitution
de commandes 49
dollar et point dinterrogation ($?) 78
donnes 176
ajouter au dbut 449, 452
distantes, accder 320
fichiers, actualiser des champs
spcifiques 276
isoler des champs 273
largeur fixe 283
longueur fixe 283
numriques 172
validation 293
DOS 178
fins de lignes, convertir en Unix 179
pause, commande 471
dos2unix 487

E
-e, option, squence dchappement (echo) 35
_echec_de_mcd_ 399
echo *, remplacer ls 12
echo, commande 32, 35, 74, 222, 342344
options et squences dchappement 539
portabilit 342
prudence dutilisation 415
cran, effacer lors de la dconnexion 438
craser un fichier 56
criture seule, expressions en 129
[05/03/08]

bash Le livre de recettes

ed, script 453


egrep 274, 378
elif, clause 116
else, clause 116
else-if (elif) 116
emacs, commandes du mode 551
Emacs et vi, chappement vers le shell 315
empreintes 328
enable, commande 14, 402
-a, afficher les commandes internes 14
-n, dsactiver les commandes internes 15
END, mot-cl (awk) 164
end_month 229
entre
caractres de dbut 64
$CEPAQUET 66
certificats SSH 70
choisir, fonction, invites et vrification
dune date de paquetage 66
commande < nomFichier 59
commande nomFichier 59
de lutilisateur 64
EOF (mot de fin dentre) 246
espaces de fin 63
/etc/inputrc, pour readline 411
fichiers core, accder aux mots de passe 69
grep, commande 60
here documents
<<, syntaxe 60
<<-, syntaxe dindentation 63
indenter pour une meilleure
lisibilit 63
inputrc, exemple de 425
$INPUTRC, pour readline 387
mot de passe, demander 69
$MOTDEPASSE 69
obtenir depuis dautres machines 354
oui/non 65
-p, option (read) 65, 69
printf 69
/proc/core, accder aux mots de passe 69
read, instruction 64
redirection avec < (infrieur ) 59
$REPLY 64, 69
root 70
-s, option (read) 69
select 68
stty sane, rparer echo 70
tabulation, caractre 64
validation 308
entres/sorties, redirection 537
env, commande 334
env (export -p) 93
environnement, paramtres de niveau
systme 417
EOF (mot de fin dentre) 246

Elodie FRITSCH <elodie.fritsch@total.com>

Index
-eq, oprateur 125
pour les comparaisons numriques 124
erasedups 394
ERR, signal 218
erreurs et fichiers core 298
ESPACE_LIBRE, fonction 249
espaces 63, 114, 277280, 281, 346
caractres 97
de dbut, supprimer 277280
incopores 97
esperluette (&), excuter des commandes en
arrire-plan 76
esperluette double (&&) 76
esperluette et suprieur (&>) 41
ET (-a) 122
ET, constructions 197
/etc/bash.bashrc 411
/etc/bash_completion 411
/etc/bashrc 411, 417
/etc/inputrc 411
/etc/passwd, fichier 17
/etc/profile 411, 417
/etc/shells 21
liste des shells valides 17
tendue des fonctionnalits 239
eval, commande 573
./examples/chargeables/ 401
-exec 192
exec, commande 356
rediriger les descripteurs de fichiers 348
exec, option 199
excutables
* (astrisque) 9
: (deux-points), sparer des rpertoires 72
&& (esperluette double), excuter le
programme suivant 76
& (esperluette), excuter des commandes en
arrire-plan 76
. (point), avec la commande ls 72
./ (point et barre oblique) 73
autorisations des fichiers 73
bg, reprendre une tche 77
bin, rpertoire 73
cd, commande 78
code de sortie ($?) 74, 78
commandes 73, 75, 76, 77
echo, commande 74
excuter des commandes depuis
variables 81
excuter une commande 71
exit 74
fg, commande, ramener une tche au
premier plan 77
for, boucle 71
hangup (hup), signal 80
identifiant de processus ($$) 77
[05/03/08]

bash Le livre de recettes

615
if, instruction 75, 78
if/then/else, branchement 71
InfoZip 82
kill, commande 80
localiser 72
messages derreur 80
nohup, commande 80
noms de variables, utiliser avec prudence 82
numro de tche 77
oublier dautoriser lexcution 485
$PATH 72
rpertoire point 72
rm, commande 78
$SCRIPT 83
scripts, excuter un ensemble de 82
set -e 79
$STAT 74
syntaxe pour les message derreur/de
dbogage 81
tches, excuter sans surveillance 79
while, boucle 79
excuter des commandes
depuis des variables 81
en arrire-plan 76
plusieurs la fois 76
plusieurs en squence 75
plusieurs scripts la fois 82
programme suivant 76
EXECUTION_FAILURE 403
EXECUTION_SUCCESS 403
exit 74, 365
exit 0 89
expand_aliases 386
expansion des accolades 571
export, commande 372
exporter
modifier des valeurs 93
variables 92, 490
denvironnement 491
expressions
arithmtiques
valuer 571
court-circuites 122
en criture seule 129, 159
entires 113
rgulires 150
confondre avec les caractres gnriques
du shell 503
correspondance de motifs 127
ext, script 61
externes, commandes 14
extglob, option (correspondance de motifs
tendue) 127
oprateurs 547
extraire les archives compresses 407
EX_USAGE. 403

Elodie FRITSCH <elodie.fritsch@total.com>

616

Index

F
-f, option (awk), boucler sur une chanes 165
-F, option (awk) dlimiter des champs 161
-F, option (ls), afficher le type des fichiers avec un
indicateur 9
-F, option (tail) 42
-f, option (tail) 42
.FAQ 27
FC (Fedora Core)
distributions Red Hat 20
fichiers rc douverture de session bash 412
personnaliser les variables $PS1 et $PS2 368
ps, commande 176
fentre de terminal remplie de charabia 496
fg, commande, ramener une tche au premier
plan 77
FICHIER1 -ef FICHIER2, trouver les fichiers
identiques 121
FICHIER1 -nt FICHIER2, comparer les dates de
modification 120
FICHIER1 -ot FICHIER2, trouver le plus
ancien 121
fichiers
$() (dollar et parenthses), pour les noms de
fichiers sur la ligne de
commande 152
.[!.]*, motifs dexpansion des noms 11
= (signe gal), dans les noms 86
.0, pages de manuel mises en forme 28
acclrer les oprations 194
actualiser des champs spcifiques 276
apostrophes 430
autorisations 73
Unix 312
caractristiques, tester 119
plusieurs 122
comparer et trouver des lignes dans 456
compresss 159, 178
comptabiliser les diffrences 446
convertir au format CSV 287
core 69, 298
et dbogage 298
CSV, analyser 288
de configuration 208211
de niveau systme 298
dcompresser 256
den-tte C 403
descripteurs 41, 348
craser 178
ET (-a) 122
/etc/passwd 17
expression court-circuite 122
.html, version HTML 28
index pour plusieurs 440

[05/03/08]

bash Le livre de recettes

info, commande 431


informations sur 8
liens symboliques 195
ls, afficher les noms 9
ls -l, afficher des dtails 9
modifier en place 452
-mtime, prdicat de find 196
options
de ls 9
de test 121
OU (-o) 122
.ps, pour les versions postscript 28
RC (initialisation) 411
crer 414416
portables 414416
rechercher
avec une liste demplacements 202
du contenu rapidement 200
existants rapidement 200
par contenu 199
par date 196
par taille 198
par type 197
Red Hat, package util-linux 431
rename, commandes 431
renommer 429, 431
restaurer les mta-donnes 439
sauts de ligne, liminer 285
sessions, journaliser 437
-size, prdicat de find 198
supprimer avec une variable vide 497
tches par lot, journaliser 437
TAILLE_FICHIER, fonction 249
temporaires et scurit 293, 304
tester 122
Texinfo 431
Zip 256, 432
fichiers MP3
$$ (dollar double), variable 253
<= (infrieur et signe gal) 250
== (signe gal double) 250
cat, commande 253
cdAnnotation 253
cdrecord 251
charger en vrifiant la place disponible 247
DIMINUER, fonction 250
ESPACE_LIBRE, fonction 249
find, commande 249
graver un CD 251
if, instruction 249
lecteur MP3 247
mkisofs 251
-A, option 253
-p, option 253
-V, option 253

Elodie FRITSCH <elodie.fritsch@total.com>

Index
fichiers MP3 (suite)
place disponible, dterminer lors du
chargement 247
TAILLE_FICHIER, fonction 249
while, boucle 249
> fichierSortie 32
FIELDWIDTHS, variable 283
file, commande 181
filtrage en sortie 351
fin du mois 229
find, commande 192
adresses IP, chercher 349351
afficher une liste de fichiers 150
capturer les mta-informations pour une
restauration 439
fichiers MP3, rechercher 249
-iname, prdicat 195
-mtime, prdicat 196
-name, prdicat 192
phrases, chercher 168
rechercher un fichier
avec une liste demplacements 202
existant rapidement 200
par contenu 199
par contenu, rapidement 200
par date 196
par taille 198
par type 197
-type, prdicat 197
xargs, commande 357
fins de lignes
convertir dUnix DOS 179
invalides 487
Firefox 1.0.7 339
fmt, commande 188
-follow, prdicat de find 195
FollowMeIP 351
fonctionnalits des scripts, tendue 239
fonctions 211
appel 265
arguments 385
dfinitions 212
viter 221
nom_fonction 402
paramtres 213
valeurs 213
for, boucle 71, 90, 96, 135, 162, 340, 357, 470
avec un compteur 135
forces, commandes SSH 329
formats viter 225
Fox, Brian 1
FreeBSD 21, 190, 204
Friebel, Wolfgang 190
Friedman, Noah 309
$FUNCNAME 215
fuseaux horaires 225, 234

[05/03/08]

bash Le livre de recettes

617

G
gawk 223
GENERER, fonction 245
gnriques, caractres 10
gestionnaires de signaux 216
getconf ARG_MAX, commande 358
getconf, utilitaire 295, 336
getdate 227
getline, commande 164
getopts 139, 258, 258261
globalisation (correspondance de motifs
tendue) 11, 127
Gnome 2.12.1 339
gnome-apt 20
GNU
bibliothque Readline 389
date, commande 223, 226, 228, 231
/etc/inputrc, pour la configuration globale
de Readline 411
find 358
formats de printf 440
grep, commande 458
~/.inputrc 412
lancer_screen, exemple 426
Linux 337
options longues 338
personnaliser Readline 412
screen, installation 433
sed, utilitaire 449
seq, utilitaire 470
Texinfo 431
Text Utils 25
The GNU Bash Reference Manual pour bash
Version 2.05b 394
xargs 358
Google Desktop Search 201
GOTO 363
grep, commande 60
apostrophe () 263
awk, sortie vers 164
-c, option 151
crer moins de lignes pour la
recherche 446
donner une source dentre 151
egrep 274, 378
expression rgulire 157
ext, script pour la paramtrisation 61
fichiers compresss 159
find, commande 400, 440
grep '<a' 263
grep -l PATH ~/.[^.]* 376
gzcat 160
-H, option 200
-h, option 150

Elodie FRITSCH <elodie.fritsch@total.com>

618
grep, commande (suite)
-i, option 154
recherches insensibles la casse 61
-l, option 151
-o, option 274
ps, commande 463
-q, option 153
recherches avec des motifs complexes 157
sortie 463
nom de fichier 271
varier laide doptions 150
texte, utilitaires de manipulation 149
tubes 155
-v, option 156
pour les recherches 156
variables, trouver certaines 95
zgrep 159
groff -Tascii 28
Groupe Bull 23
gsub 282
Guide avanc dcriture des scripts Bash 28
guillemets (") 33, 263, 572
supprimer 186
gunzip, utilitaire 407
gzip, compression de fichier 178

H
-h, obtenir de laide 7, 14
-H, option (grep) 200
-h, option (grep) 150
hachages 165, 320
sens unique 320
hangup (hup), signal 80
hash -r, commande 297
head, commande 42
hello.c 401
help, commande 15
--help, option 7, 14
here document 60
<<-, pour indenter 63
<<, syntaxe 60
comportement trange dans 61
donnes places dans le script 60
HTML dans les scripts 246
indenter pour une meilleure lisibilit 63
hexdump 346
hier, obtenir la date avec Perl 232
histappend 395
$HISTCONTROL, variable 394
$HISTFILE, variable 394
$HISTFILESIZE, variable 394
$HISTIGNORE, variable 394
historique
!! (point dexclamation double),
oprateur 155

[05/03/08]

bash Le livre de recettes

Index
automatiser le partage 393
~/.bash_history, fichier denregistrement des
commandes 412
volutions de bash 27
fixer les options du shell 393
histogramme 166
history, commande 393
numro dhistorique 374
synchronisation entre sessions 392
history, commande 393
$HISTSIZE, variable 394
$HISTTIMEFORMAT, variable 394
homme du milieu, attaques 328
horaires dt 235
Host_Alias 318
hte externe 350
HP 26
HP-UX 23, 190
.html 28
HTML, analyser 262
html, .html pour les versions HTML 28

I
$i
dans awk 163
ne pas utiliser 90
voir aussi $x
-i, option
(grep), recherches insensibles la casse 61
(xargs) 194
IBM 23
identifiant de processus ($$) 77, 464
$ID_SSH 355
if, commande 378
if, instruction 75, 78, 105, 116, 249
if liste 117
if, test 102
ifconfig 349
$IFS (Internal Field Separator) 263, 267, 277,
279, 298
$IFS=: 203
syntaxe portable 299
if/then, identifier des options 257
if/then/else, branchement 71
ignoreboth 394
ignoredups 394
ignorespace 394
-iname, prdicat de find 195
$include (readline) 209, 388
inclure la documentation dans les scripts
shell 88
incopores, espaces 97
indenter pour une meilleure lisibilit 63
index de plusieurs fichiers 440

Elodie FRITSCH <elodie.fritsch@total.com>

Index

619

indicateurs 169, 258


boolens 210
infrieur (<) 59
infrieur et signe gal (<=) 250
info, commande 431
info2man, afficheur et convertisseur
Texinfo 432
info2www, afficheur et convertisseur
Texinfo 432
InfoZip 82, 296
initialisation, fichiers (RC) 411
.inputrc 387
~/.inputrc 412
inputrc, exemple de 425
$INPUTRC, variable 387
INSTALL, instructions dinstallation de bash 27
instructions
let 113
select 390
intgrit du systme 293
interfaces grahiques 20
Rpmdrake 20
Internal Field Separator ($IFS) 263, 277, 279,
298
internal_getopt 403
.INTRO 27
Introduction aux scripts shell (ditions
OReilly) 26, 292
invites
# (dise), reprsenter root 4
$ (dollar) en fin, signalant un utilisateur
normal 4
~ (tilde), rpertoire personne 4
0m, effacer tous les attributs et supprimer les
couleurs 375
afficher
avec loption -p (read) 65, 69
tout 370
chanes 372
changer sur les menus simples 143
chercher et excuter des commandes 6
choisir, fonction 66
exemples simples 368
garder courtes et simples 374
-L, option (pwd, cd), afficher le chemin
logique 5
mot de passe, demander 69
-P, option (pwd, cd), afficher lemplacement
physique 5
par dfaut 4
personnaliser 368, 507
$PROMPT_COMMAND 374
promptvars 372
$PS1, invite de commande 372

[05/03/08]

bash Le livre de recettes

$PS2, invite secondaire 390


$PS3, invite de select 372, 390
$PS4 392
pwd, commande 5
qui a fait quoi, quand et o 370
rpertoire de travail 5
root 5
secondaires 390
select 68, 142
su, commande 5
sudo, commande 5
tlchargements pour ce livre 371
xtrace 372
invoquer bash 505
ISO 8601, afficher des dates et des heures 225

J
-j, pour bzip2 179
jetons, traitement sur la ligne de commande 569
jour de la semaine pour le jour indiqu 229
journaliser 437
JOURS, utiliser avec prudence 229
.jpg 126

K
k (kilo-octets) 199
Kernighan, Brian 333
keychain 321, 325327
kill, commande 80, 408
kill -l 215, 219
Knoppix 20
kpackage 20

L
-l chpass, changer de shell par dfaut 17
-l, option (grep) 151
-l, option (ls), afficher une liste longue 9
-L, option (ls), obtenir les informations de
liens 9
-L, option (pwd, cd), afficher le chemin
logique 5
lancer_screen, exemple 426
largeur fixe, donnes de 283
Le shell bash, 3e dition (ditions OReilly) 26,
314, 400, 406
lecteur MP3, charger 247
less, commande 47, 160, 189
-V, option 468
$LESS, variable 189
lesspipe* 190
lesspipe.sh 190
let, instruction 113
liens symboliques 195, 246, 386

Elodie FRITSCH <elodie.fritsch@total.com>

620
lignes
compter 187
den-tte 43
en double, supprimer 177
numroter 467
Linux
Ajout/Suppression dapplications 20
API Linux
mulation 24
fonctionnalit 24
applications
installation 18
mettre niveau 18
/bin/bash 386
CentOS 20
crontab 235
Debian 18
/etc/apt/sources.list 20
/etc/profile 378
FC (Fedora Core) 20
fichiers DOS, passer sous Linux 185
gnome-apt 20
info 431
interface grahique 20
Rpmdrake 20
Knoppix 20
kpackage 20
Linux Security Cookbook (OReilly
Media) 327
Mandrake 20
Mandriva 20
MEPIS 20
message derreur 20
ordre de tri 175
$PATH, changer 412
Red Hat 378
Red Hat Enterprise Linux (RHEL) 20, 204
root 18
SUSE 20, 190
Synaptic 20
tarball.tar.gz 179
Ubuntu 339
versions de bash 18
Vixie Cron 235
YaST 20
Linux Security Cookbook (OReilly Media) 321
lisibilit, amliorer par lindentation 63
liste
commandes internes 14
du contenu, afficher avec tar -t 182
lithist 395
Live CD 20
locate 200
trouver des fichiers ou des commandes 7
logger, utilitaire 348, 359

[05/03/08]

bash Le livre de recettes

Index
Logiciels pour NetBSD 22
logmsg 365
longueur fixe, donnes de 283
loptend 403
ls, commande 9
-a, option 9, 10
afficher les noms de fichiers 7
-d, option 10
-F, option 9
-l, option 9, 161
-L,option 9
options 9
-Q, option 9
-R, option 9
-r, option 9
-S, option 9
lynx 350

M
m (caractre), indiquer une squence
dchappement pour la couleur 375
Mac OS X
10.4 et curl 350
bash-2.05 22
/bin/sh 22
BSD 338
chsh, ouvrir un diteur 17
cut, commande 176
Darwin 22
DarwinPorts 22
Fink 22
HMUG 22
Mac OS 10.2 (Jaguar) 22
Mac OS 10.4 (Tiger) 22
shell par dfaut 3
sources de bash 22
sudo 455
versions de bash 22
Macdonald, Ian 406
machines virtuelles prconstruites 339
macros pour la documentation du shell 377
mail 360
compatibilit MIME 361
mail* 361
mailto 360
MAILTO, variable 361
mailx 360
Matrise des expressions rgulires, 2e dition
(ditions OReilly) 275
Makefile 401
man, commande 7
man sudoers 318
Mandrake 20
Mandriva 20

Elodie FRITSCH <elodie.fritsch@total.com>

Index

621

mcanisme de rptition, pour les recherches


(\{n,m\}) 158
menus 142
MEPIS 20
messages
de journalisation, supprimer par erreur 156
derreur 40, 80, 108, 260, 382
Permission non accorde 485
dutilisation 211
Meta Ctrl-V, afficher une variable pour sa
modification 378
meta-caractres 569
Midnight Commander 303
milliers, sparateur des 472
mises jour des chemins 376
mkdir, commande 399
mkdir -p -m 0700 $rep_temp, viter la
concurrence critique 305
mkisofs, commande 251
-A, option 253
-p, option 253
-V, option 253
mktemp 305
modes
emacs, commandes du 551
octal 310
vi, commandes du 553
modifier des valeurs exportes 93
mot de fin dentre (EOF) 246
$MOTDEPASSE 69
moteur de recherche locale 201
mots
compter 187
inverser lordre 162
rservs 45
mots de passe 311, 320, 321
demander 69
mots-cls, traitement sur la ligne de
commande 569
mpack 362
-mtime, prdicat de find 196
multiplateformes, scripts 339
multiplication, symbole de 148
mysql, commande 272
MySQL, configurer une base de donnes 271

N
N fichiers de journalisation 460, 463
-n, option (sort), trier des nombres 172
-name, prdicat de find 192
-name '*.txt', rduire la recherche avec find 200
NetBSD 21, 175
Netcat (couteau suisse de TCP/IP) 348, 359
NEWS, changements dans les versions de
bash 27

[05/03/08]

bash Le livre de recettes

NF, variable (awk) 162


boucler sur des chanes) 165
\{n,m\}, rptition des expression rgulires 158
noclobber, option 55
nohup, commande 80, 208
nombre de jours entre deux dates 229
-nombre, option (head, tail), changer le nombre
de lignes 42
nombres 163, 472
nom_fonction, fonction 402
noms
de chemins
complter avec la touche Tab 481
expansion 571
pluriels 268
signaux 408
noms de fichiers
${}, argument 110
/ (barre oblique) 110
{}, contient des noms pendant lexcution
dune commande 200
$() (dollar et parenthses), pour les noms de
fichers sur la ligne de
commande 152
= (signe gal) dans 86
alatoires pour la scurit 304
.bof, se terminant par 110
caractres tranges dans 193
caractristiques dun fichier, tester 119
dlimiter
la rfrence 110
les substitutions 110
expansion 11
for, boucle 110
gestion spciale 600
.jpg 126
ls, commande 9
modifier 429
mv, commande 110
oprateurs de manipulation de chanes 111
protection 98
recherches 151
renommer 109
significatifs 305
trouver 193
NON, constructions 197
non privilgis, utilisateurs 293
non-root, assaillant 305
no_options(list) 403
NOPASSWD, option 319
NOTES, notes de configuration et de
fonctionnement 27
NPI (notation polonaise inverse) 145
calculatrice 144
NTP (Network Time Protocol) 223, 233

Elodie FRITSCH <elodie.fritsch@total.com>

622

Index

NULL 403
null 106
numros
de scurit social, rechercher 158
de signaux 216
de tche (voir identifiant de processus)
de tlphone, script 60
numroter les lignes 467

OU (-o) 122
oui/non, entre 65
outils
de virtualisation gratuits 339
sans ligne de commande 350
Outlook 361

-p, option (mkisofs) 253


-P, option (pwd, cd), afficher lemplacement
physique 5
-p, option (read) 69
afficher une invite 65
-p, option (trap) 218
pages de manuel 7, 28
mettre en forme 28
rechercher des expressions avec apropos 7
paire de cls, crer 321
paragraphes, reformater 188
${paramtre#[#]mot} 503
${paramtre%[%]mot} 503
${paramtre/motif/chane} 503
paramtres
$*
erreurs dutilisation 99
sans les guillemets 100
$@, sans les guillemets 100
de profil de niveau systme 417
denvironnement de niveau systme 417
dsaffecter 108
erreurs dans 99
espaces incopores 97
expansion 108
fonctions 213
guillemets autour 98
${paramtre#[#]mot} 503
${paramtre%[%]mot} 503
${paramtre/motif/chane} 503
positionnels, arguments 106
${!prfixe*}, pour la compltion
programmable 299
${!prfixe@}, pour lexpansion 299
rgionaux pour le tri 175
-V (mkisofs) 253
parenthses (()) 45, 197
parenthses doubles ((())), construction 132
passage par valeur 93
passwd
changer de shell par dfaut 17
-e, changer de shell par dfaut 17
patch, programme 441, 445
$PATH, variable 6, 72, 202, 294, 376, 377382
PATH="nouv_rp:$PATH' 377
PATH="$PATH:nouv_rp" 377
pause, commande (DOS) 471

objets partags dynamiques 405


octal, mode 310
octets 199
od, commande 347
ODF (Open Document Format) 254, 285
OFS (sparateur de champs de sortie de
awk) 282
Open Document Format (ODF) 254, 285
OpenBSD 21, 291
OpenSSH 291, 321, 331
oprateurs
:- (affectation) 106
?, correspondance de motifs du shell 11, 546
:+ (de variable) 211
!! (point dexclamation double),
historique 155
>> (suprieur double) 120
, (virgule) 115
-a 120
comparaison 125
correspondance de motifs tendue 11
daffectation 114
de comparaison 125
de redirection 41
de test 536
-eq 125
comparaisons numriques 124
manipulation de chanes 111
Perl 125
*.txt, pour la correspondance de motifs 11
*txt, pour la correspondance de motifs 11
oprations, acclrer 194
option nomFichier 121
options
de dmarrage 368
dsactiver interactivement 368
dhistorique 393
et arguments 258
fixer au dmarrage 368
option nomFichier 121
promptvars 372
-s (exemple de commande interne
chargeable) 401
seules 258
OU, constructions 197

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Index
PC-BSD 339
PCRE (Perl Compatible Regular
Expressions) 275
Perl 89, 125, 231, 235, 275
structure de donnes pour la date et
lheure 230
Perl Cookbook, Second Edition (OReilly
Media) 473
Permission non accorde, message derreur 485
personnels, utilitaires 389
phases 363
photos 241
afficher dans un navigateur 242
phrases
chercher 168
cls 168
de passe, changer et protection 321
piles 476
pinfo, afficheur et convertisseur Texinfo 432
pkg_add
installer/mettre jour bash 21
-vr, option 22
place disponible, dterminer sur un lecteur
MP3 247
pluriel, fonction 269
pn_day 229
pn_day_nr 229
pn_month 229
pn_weekday 229
POD (Plain Old Documentation) 89
pod2*, programmes 89
point (.) 157
fichiers 10, 11, 209
rpertoire 72
point dexclamation (!), inverser une classe de
caractres 11
point dexclamation double (!!), oprateur pour
lhistorique 155
point dinterrogation (?) 11, 126
correspondre un seul caractre 126
oprateur de correspondance de motifs du
shell 11, 546
point et astrisque (.*) 157
avec les caractres gnriques de fichiers 11
point et barre oblique (./), accder au rpertoire
de travail 7
points au dbut des noms de fichiers 414
point-virgule (;) 76, 117
Polar Home 26
popd, commande interne 476
portabilit, problmes 295
POSIX 174, 219, 295, 334, 335, 384
pourcent (%), dfinir des formats 34
pr, commande 188
Practical UNIX & Internet Security (OReilly
Media) 292
[05/03/08]

bash Le livre de recettes

623
prdicats 192
${!prfixe@} 299
${!prfixe*}, pour les paramtres de la
compltion programmable 299
prefixe_significatif, et scurit 306
-print, condition (find) 192
-print0 (find, xargs -0) 193
printf 34, 69, 140, 342, 497, 540
prive, cl 321
problmes de portabilit 295
/proc/core, accder aux mots de passe 69
processus
automatiser 363365
vrifier lexcution en cours 464
~/.profiles 412
$PROMPT_COMMAND, variables 374
protection
(apostrophe) 13, 157, 220
conserver les espaces dans la sortie 33
(apostrophes inverses) 49
\ (barre oblique inverse) 13
" (guillemets) 12, 491
conserver les espaces 33
texte sans 12
$*, sans les guillemets 100
$@, sans les guillemets 100
dans les arguments 34
erreurs commande non trouve 491
espaces de fin 13
ligne de commande 12, 572
noms de fichiers 98
paramtres 98
-Q, option (ls), noms entre guillemets 9
rfrences de variables 98
$VAR, expression 124
.ps 28
ps, afficher les mots de passe sur la ligne de
commande 311
$PS1, variable 368, 372, 428
$PS2, variable 368, 390
$PS3, variable 372, 390
$PS4 372, 392
PTY, numro de pseudo-terminal 369
*.pub, cl publique 321
publique, cl 323
pushd, commande 476
pwd, commande 5
$PWD, variable 373

Q
-q, option (grep) 153
-Q, option (ls), noms entre guillemets 9
questions frquemment poses
additionner une liste de nombres 164
adresses IP, trouver 354

Elodie FRITSCH <elodie.fritsch@total.com>

624

Index

questions frquemment poses (suite)


attaques par usurpation
viter 294
sur linterprteur 294
awk 160
bash
documentation officielle 27
shell par dfaut 17
trouver pour #! 335
boucler sur une chane 166
chmod, commande 56
comptes shell gratuits 26
diffrences des shells UNIX 29
donnes
ajouter au dbut dun fichier 452
carter certaines parties 161
sous forme dhistogrammes 168
crire des squences 471
.FAQ 27
fichiers
autorisations 56
modifier sur place 454
point (.) masqus 12
supprimer ou renommer ceux
contenant des caracres
spciaux 448
inverser lordre des mots 163
noclobber, option 55
paragraphes de texte aprs une phrase
trouve 169
pause, commande DOS 473
protocole syslog de BSD 349
rpertoire de travail dans $PATH, viter 303
RFC 3164 349
tester des scripts 338
tubes et sous-shells 496
xargs, erreurs liste darguments trop
longue 358

R
-r, option (ls), inverser lordre de tri 9
-R, option (ls), parcourir rcursivement des
rpertoires 9
r00t 293
ramener une tche au premier plan 77
Ramey, Chet
=~, et les expressions rgulires dans
bash 503
for, boucle 358
Mac OS 10.2 (Jaguar) 22
Mac OS 10.4 (Tiger) 22
site web pour bash 22, 27
utiliser printf avec des paramtres
rgionaux 472
validation de lentre 309

[05/03/08]

bash Le livre de recettes

$RANDOM 304
.rbash.0 28
rbash.1, page de manuel du shell 28
RE (expression rgulire) 157, 164
read, instruction 64, 134, 266, 267
readline 209, 377, 387
readline.3, page de manuel de readline 28
README, description de bash 27
recherches
Beagle, moteur de recherche 201
chercher et remplacement globalement 263
command, commande 204
complexes 157
Copernic Desktop Search 201
ET, constructions 197
expressions dans les pages de manuel,
commande apropos 7
fichier 200, 202
par contenu 199
par date 196
par taille 198
par type 197
-follow, prdicat de find 195
Google Desktop Search 201
-i option (grep), recherches insensibles la
casse 61
$IFS=: 203
-iname, prdicat de find 195
insensibles la casse 61, 154
-l, option, avec grep 151
locate 200
mcanisme de rptition 158
moteur de recherche locales 201
-mtime, prdicat de find 196
-name '*.txt', rduire la recherche avec
find 200
\{n,m\}, mcanisme de rptition 158
noms de fichiers 151
NON, constructions 197
numro de scurit social 158
OU, constructions 197
$PATH 202
phrases 168
rduire 156
-size, prdicat de find 198
slocate 200
source, commande 202
Spotlight, moteur de recherche locale 201
tubes 154
-type d, trouver des rpertoires 198
type -P 202
-type, prdicat de find 197
-v, option (grep) 156
${variable/motif/remplacement} 202
vrai/faux 152

Elodie FRITSCH <elodie.fritsch@total.com>

Index
Red Hat 190, 203, 317, 334, 431
Red Hat Enterprise Linux (RHEL) 20, 204
redirection
des entres/sorties 537
du rseau 348, 359
oprateurs de 41
rels, arguments 103
rfrences en ligne, scurit du shell 292
relatifs, chemins 38
remplacer
des caractres 183
et rechercher globalement 263
rename, commande 431
base sur Perl 431
rpertoires 377
ajouter ou supprimer 377
$CDPATH, variable 384
crer et y aller en une tape 398
dapplications 377
de lutilisateur 377
de travail 373
ajouter $PATH 303
erreurs de $PATH 488
find, commande, utiliser dans de nombreux
niveaux 399
modifiables par tous 300302, 377
photos, afficher 241
sauvegarde 460, 463
se dplacer parmi 475
sparer avec des deux-points (:) 72
temporaires 293
$REPLY, variable 64, 69, 277281
$rep_temp 305
requte SQL 227
rseau, rediriger 348, 359
reset_internal_getopt 403
restauration de sessions 433, 436
restriction dhte 330
$resultat 355
RETURN, signal 218
rm, commande 49, 78
Robbins, Arnold 292
Robbins, Daniel 325, 327
root, compte 4, 376
ROT13 320
ROT47 320
RPM (Red Hat Package Manager) 23, 180
.rpm (voir aussi .deb) 180
Rpmdrake, outil graphique 20
rsh (Remote Shell) 315
rssh 331
rsync 329

[05/03/08]

bash Le livre de recettes

625

S
-S, option
(ls), trier par taille de fichier 9
(sort), dsactiver le tri stable 175
-s, option
exemple de commande interne
chargeable 401
read, commande 69
sauts de ligne
avec echo, option -n 35
liminer 285
sauvegarde, rpertoires de 460, 463
/sbin/ifconfig -a 351
Schneier, Bruce 291
scp, sans mot de passe 321
screen
mises en garde 434
mode commande (touche meta) 435
partager une session bash 436
$SCRIPT, variable 83
scripts 211, 437
${#} 101
{} (accolades) 92, 96
(apostrophe) 263
@ (arobase) 211
/ (barre oblique) 110
[] (crochets simples) 131
: (deux-points) 88
:= (deux-points et signe gal) 107
# (dise) 87
$* (dollar et astrisque) 96
" (guillemets) 263
autour des paramtres 98
${:=}, oprateur 106
:-, oprateur daffectation 106
>, oprateur de redirection 208
:+, oprateur de variable 211
(()) (parenthses doubles), construction 132
. (point) 209
; (point-virgule) 117
${#}, pour lanalyse directe 257
$*, sans les guillemets 100
$@, sans les guillemets 100
>> (suprieur double), oprateur 120
${:-}, syntaxe 104
${:?}, syntaxe 108
$0, variable 245
${1:0:1}, test du premier caractre du
premier argument 257
<a>, balises 262
-a, oprateur 120
AFFICHER_ERREUR, fonction 245
albums photo 242246
appel de fonction, analyser la sortie 265

Elodie FRITSCH <elodie.fritsch@total.com>

626

Index

scripts (suite)
appel par valeur 93
arguments 96, 101, 109, 240
analyser 257
doption 103
awkt 182
basename, commande 141
~/bin, rpertoire 389
.bof, se terminant par 110
capturer les signaux 215, 215219
caractre
par dfaut pour le papier et lcran 91
un la fois 269
caractristiques dun fichier, tester 119
case, instruction 259
identifier des options 257
cat, commande 246
chanes constantes, utiliser pour les valeurs
par dfaut 107
charger 209
chercher et remplacement globalement 263
commandes combines 119
commentaires 87
comparer le contenu de documents 254
comportement, modifier 130
compte root 4
configure 405
construction conditionnelle 116
correspondance de motifs, sensibilit la
casse 127
dboguer 500
DEBUG, signal 218
dbuter des commentaires 102
dcompresser des fichiers 256
dcouper une ligne 91
dfinitions de fonctions 212
dlimiter les substitutions 110
dmon 207
diff, comparer le contenu de deux
documents 256
documentation 87
pour lutilisateur 88
documents, comparer 254
crire 3
ed 453
else, clause 116
else-if (elif) 116
env (export -p) 93
EOF (mot de fin dentre) 246
erreurs commande non trouve 212
espaces 90, 97
tendue des fonctionnalits 239
excuter
le jour N 235
un ensemble de 82
exit 0 89
[05/03/08]

bash Le livre de recettes

expansion arithmtique 108


expression rgulires, pour la
correspondance de motifs 127
extglob, option (correspondance de motifs
tendue) 127
FICHIER1 -ef FICHIER2, trouver les fichiers
identiques 121
FICHIER1 -nt FICHIER2, comparer les dates
de modification 120
FICHIER1 -ot FICHIER2, trouver le plus
ancien 121
fichiers
de configuration 208211
Zip 256
fonctions 90
bash 211
for, boucle 90, 96, 110
GENERER, fonction 245
gestionnaires de signaux 216
getopts 139, 258
arguments 258261
grep, commande 95, 263
here document 88, 246
HTML, analyser 262
$i, variable, ne pas utiliser 90
voir aussi $x
if, instruction 105, 116
if liste 117
if, test 102
$IFS (Internal Field Separator) 267
if/then, identifier des options 257
$include 209
indentation 90
indicateurs 258
keychain 326
kill -l 215, 219
liens symboliques 246
ligne de tirets, afficher 239
lisibilit 90
messages
de journalisation, supprimer par
erreur 156
derreur 108, 260
modifier des valeurs exportes 93
mots de passe 319
mv, commande 110
navigateur, afficher des photos 242
nophytes 291
nohup, commande 208
nom pluriel 268
NOPASSWD, option 319
null 106
numros de signaux 216
ODF (Open Document Format) 254
oprateurs de manipulation de chanes 111

Elodie FRITSCH <elodie.fritsch@total.com>

Index
scripts (suite)
options
avec des arguments 258
de test des fichiers 121
seules 258
-p, option (trap) 218
paramtres 95, 97, 106, 108
de fonctions 213
Perl 89
pluriel, fonction 269
POD (Plain Old Documentation) 89
printf 140
problmes de scurit 293
read, instruction
analyser du texte 266
convertir en tableau 267
readline 209
recherches
complexes 157
rduire 156
redirections 130
rpertoire 241, 303
RETURN, signal 218
sauts de lignes 90
scp, sans mot de passe 321
sparateur de champs 263
set, commande 94
setgid 312
setuid 312
shift, commande interne 140, 259
sortie
convertir en tableau 264
crire par plusieurs instructions 35
sous-chane, fonction 269
STDERR (>&2) 208
STDIN (entre standard) 208
STDOUT (sortie standard) 208
substitution de commandes 108
syntaxe
en criture uniquement 87
vrifier lexactitude 499
tableau 111, 264
test
commande 118
viter ce nom 489
test -t, option 130
then (if) 117
tilde (~), pour lexpansion 108
/tmp/ls, malveillant 303
trap, utilitaire 215
tty 207
USAGE, fonction 245
-v, option 104, 361
valeurs
de fonctions 213
par dfaut 104, 105
[05/03/08]

bash Le livre de recettes

627
validation des donnes 293
${#VAR} 102
${VAR#alt} 102
variables 92, 94, 501
erreurs dans 99
noms 90, 92
rfrences, utiliser la syntaxe
complte 92
tableaux 111
$VERBEUX 104
while, boucle 131, 133
while read 132
$x, syntaxe 90
xtrace, dboguer 501
zro, valeur de retour 132
scripts labors
{} (accolades) 355
adresses IP
chercher 349351
externes et routables 350
agent de transfert du courrier 360
architecture x86 339
ARG_MAX 358
limites en octets 358
arguments
dcomposer 357
liste trop longue, erreur 357
bash, rediriger le rseau 359
#!/bin/sh, viter dutiliser 334
Browser Appliance v1.0.0 339
BSD 338
caractres non imprimables 346
case, instruction 363
client de messagerie 362
command, commande 337
-p, option 337
courrier lectronique, envoyer 360362
couteau suisse de TCP/IP (Netcat) 359
cron 361
CS_PATH 336
curl 350
descripteurs de fichiers 348
distribution bureautique base sur KDE 339
echo, commande 342344
portabilit 342
entre, obtenir depuis dautres
machines 354
env, commande 334
espaces 346
exec, commande 356
rediriger les descripteurs de fichiers 348
exit 365
filtrage en sortie 351
find, commande 357
Firefox 1.0.7 339
FollowMeIP 351

Elodie FRITSCH <elodie.fritsch@total.com>

628
scripts labors (suite)
for, boucle 357
portables 340
getconf ARG_MAX, commande 358
getconf, utilitaire 336
Gnome 2.12.1 339
GNU, options longues 338
GOTO 363
hexdump 346
hte externe 350
$ID_SSH 355
ifconfig 349
logger, utilitaire 348, 359
logmsg 365
lynx 350
Mac OS X 338
Mac OS X 10.4 et curl 350
machines virtuelles prconstruites 339
mail 360
compatibilit MIME 361
mail* 361
mailto 360
MAILTO, variable 361
mailx 360
mpack 362
multiplateformes 339
viter 337
Netcat (couteau suisse de TCP/IP) 348, 359
od, commande) 347
outils
de virtualisation gratuits 339
sans ligne de commande 350
Outlook 361
$PATH de POSIX, fixer 335
PC-BSD 339
phases 363
portables, chercher bash 334
portables, crire 333, 337
POSIX 334
printf "%b" message 342
processus, automatiser 363365
Red Hat 334
redirection du rseau 348
$resultat 355
/sbin/ifconfig -a 351
shopt -s nullglob, dvelopper les fichiers en
chanes nulles 358
Solaris 338, 347
sortie
afficher en hexadcimal 346
dcomposer 345
rediriger pour lintgralit dun
script 356
split, commande 345

[05/03/08]

bash Le livre de recettes

Index
SSH avec des cls publiques 354
stocker des scripts et des donnes de test avec
NFS 339
substitution de commandes 354
syslog
messages 348
priorits 349
utiliser 359
tester sous VMware 339
Thunderbird 361
trafic rseau 348
Ubuntu Linux 5.10 339
UDP 348
/usr/bin/env, commande 334
$UTILISATEUR_SSH 355
uuencode 360
-v, option 361
VMware 338
console base sur VNC 339
VMware Player 339
VMware Server 339
wget 350
xargs, commande 357
xpg_echo 342
sdiff 458
secondes 234, 235
depuis lorigine 230, 231, 234
scurit
--clean (keychain), vider les cls SSH en
cache 326
accder des donnes distantes 320
AIDE 293
alias
effacer 296
malveillants 296
AppArmor 317
assaillant non-root 305
autorisations, fixer 310
barre oblique inverse (\) au dbut,
supprimer lexpansion des alias 297
~/bin, problmes de scurit 390
chemins
absolus 295
srs 294
cheval de Troie 293
chroot
commande 316
prisons 316
cl
prive 321
publique 323
commandes mmorises 297
commentaires, modifier 321
comptes partags 314

Elodie FRITSCH <elodie.fritsch@total.com>

Index
scurit (suite)
concurrence critique 293
viter 305
contrles daccs obligatoires 317
crypt, commande 320
dbordement de tampons 293
du shell, rfrences en ligne 292
Emacs et vi, chappement vers le shell 315
empreintes 328
entre, validation 308
fichiers
core 298
et dbogage 298
temporaires 293, 304
getconf, utilitaire 295
groupes Unix 312
hachage sens unique 320
hash -r, commande 297
homme du milieu, attaques 328
Host_Alias 318
$IFS (Internal Field Separator) 298
syntaxe portable 299
intgrit du systme 293
keychain 321, 325327
man sudoers 318
mkdir -p -m 0700 $rep_temp, viter la
concurrence critique 305
mktemp 305
mots de passe 311, 319, 320
noms de fichiers
alatoires 304
significatifs 305
NOPASSWD, option 319
OpenSSH Restricted Shell 331
paire de cls, crer 321
$PATH 294
phrase de passe 321
POSIX 295
prefixe_significatif 306
problmes
classiques 293
de portabilit 295
ps, afficher les mots de passe sur la ligne de
commande 311
*.pub (cl publique) 321
r00t 293
$RANDOM 304
rbash, restreindre les shells de
connexion 314
Red Hat Linux 317
rpertoires
modifiables par tous 300302
temporaires 293
$rep_temp 305
restriction dhte 330

[05/03/08]

bash Le livre de recettes

629
ROT13 320
ROT47 320
rsh (Remote Shell) 315
rssh 331
rsync 329
scp, sans mot de passe 321
SELinux (Security Enhanced Linux,
NSA) 317
sessions inactives 331
setgid 312
setuid 312
setuid root, usurpation 294
shebang, ligne 294
shell
Bourne 315
restreint 314
SSH, commandes 321, 329331
ssh-add, commande 325
ssh-agent 321
ssh-keygen, (ssh-keygen2) 321
stratgie 317
sudo bash 318
sudoers 318
tches cron sans mot de passe 321
techniques de programmation 292
$TMOUT, variable 331
/tmp/ls, script malveillant 303
trap, configurer 305
Tripwire 293
ulimit 298
umask fiable 299
$UMASK, variable 299
\unalias -a, commande 296
Unix, autorisations des fichiers 312
urandom 305
User_Alias 318
utilisateurs
inactifs 331
invits, restreindre 314
non privilgis 293
non-root 317
utilitaires infests 293
validation des donnes 293
vi et Emacs, chappement vers le shell 315
visudo, pour les modifications 319
Security Enhanced Linux, NSA (SELinux) 317
sed, programme 149, 287
select, invite ($PS3) 68, 142, 372, 390
SELinux (Security Enhanced Linux, NSA) 317
sensibilit la casse 138, 184
sparateurs
de champs 174, 263, 282
de nombres 472
seq, commande, gnrer des valeurs en virgule
flottante 136

Elodie FRITSCH <elodie.fritsch@total.com>

630
squences dchappement 35, 185
ANSI 370
couleurs 508
pour la couleur, m (caractre) 375
squences, crire 469
sessions 331, 392, 433, 436, 437
set, commande 94, 387, 505
set -e 79
set -o functrace, option 218
set -o posix 219
setgid 312
setuid 312
setuid root, usurpation 294
SGI 23
shebang, ligne 294
shells
$-, liste des options en cours 16
adapter lenvironnement 386
barre oblique inverse (\), pour
lexpansion 13
bash 16
~/.bash_login, fichier de profil personnel des
shells de session Bourne 411
Bourne (sh) 1, 3, 315, 411
/etc/profile, fichier global
denvironnement de session 411
C (csh) 1
caractres gnriques, confondre avec les
expression rgulires 503
cd, commande 399
chpass -s shell, changer de shell par
dfaut 17
chsh
changer les paramtres dans 17
-l, lister les shells valides 17
-s /bin/bash, faire de bash le shell par
dfaut 17
-s, changer de shell par dfaut 17
commandes internes pour ignorer des
fonctions et des alias 221
comptes gratuits 25
Cygwin 3
de root, changer sous Unix 17
/dev/nul, pour les scripts portables 153
Emacs, chappement vers le shell 315
enable -n, dsactiver les commandes 15
/etc/bash.bashrc (Debian), fichier
denvironnement global de sousshell 411
/etc/bashrc (Red Hat), fichier
denvironnement global pour les
sous-shells 411
/etc/shells 21
expand_aliases 386
fonctions 211, 229

[05/03/08]

bash Le livre de recettes

Index
historique, entre des sessions et
synchronisation 392
$IFS (Internal Field Separator) 263, 277, 279
inclure la documentation dans les scripts 88
Korn (ksh) 1
-l, option 17
macros pour la documentation 377
niveaux 369
OpenBSD 291
OpenSSH 291
OpenSSH Restricted Shell 331
options dhistorique, fixer 393
par dfaut
sous Linux 3
sous Mac OS X 3
parenthses (()), rediriger lexcution dun
sous-shell 45
passwd
changer de shell par dfaut 17
-e, changer de shell par dfaut 17
portables, crire 337
~/.profile, fichier de profil personnel pour les
shells de session Bourne 412
promptvars,, option 372
rbash, restreindre le shell de connexion 314
.rbash.0, page de manuel 28
restreints 314
rsh (Remote Shell) 315
scripts, crire 3
scurit
des scripts 291
rfrences en ligne 292
set 387, 505
Shell Corner: Date-Related Shell Functions
dans UnixReview 229
shell.h 403
shopt 387
shopt -s, commande, activer des options 127
sous-shells 45
SSH, le shell scuris La rfrence
(ditions OReilly) 321, 328
standard 1
techniques de programmation 292
tester des scripts sous VMware 339
tube, crer des sous-shells 493
Unix 2
usermod -s /usr/bin/bash, changer de shell
par dfaut 17
valides, liste dans /etc/shells 17
variables, tester lgalit 124
vi et Emacs, chappement vers le shell 315
Writing Shell Scripts, documentation 28
shift, commande interne 140, 240, 259
shopt, commande 387
-s, activer des options du shell 127

Elodie FRITSCH <elodie.fritsch@total.com>

Index

631

shopt, commande (suite)


-s nocasematch
modifier la sensibilit la casse 129
pour bash versions 3.1+ 138
-s nullglob, dvelopper les fichiers en chanes
nulles 358
_signaux 409
signaux, noms 408
signe gal (=) 86, 114
signe gal double (==) 250
Silverman, Richard 321, 329
-size, prdicat de find 198
slocate 200
trouver des fichiers ou des commandes 7
Solaris 176, 338
cut, commande 176
environnements virtuels 338
less 190
versions
2.x 23
7 23
8 23
sort, commande 171, 173
-t, option 174
-u, option, supprimer les doublons lors du
tri 173
sortie
{} (accolades), regrouper la sortie 44
(apostrophe), conserver les espaces 33
| (barre verticale), tube 46
$() (dollar et parenthses), pour la
substitution de commandes 49
&> (esperluette et suprieur ), envoyer
STDOUT et STDERR vers le mme
fichier 41
" (guillemets), conserver les espaces 33
() (parenthses), rediriger lexcution dun
sous-shell 45
+ (plus ), dcaler depuis le dbut du
fichier 43
> (suprieur )
rediriger des fichiers 38
rediriger la sortie 36, 50
>> (suprieur double), ajouter la sortie 41
>& (suprieur et esperluette), envoyer
STDOUT et STDERR vers le mme
fichier 41
afficher
en hexadcimal 346
la fin dun fichier 42
le dbut dun fichier 42
ajouter un prfixe ou un suffixe 465
appel de fonction 265
avec tampon 52
benne bits 44

[05/03/08]

bash Le livre de recettes

connecter deux programmes 46, 49


contrler le placement de 34
convertir en tableau 264
dcomposer 345
descripteur de fichier 41
devier, script 50
/dev/null 44
echo, commande 32
craser 54
un fichier 56
liminer 44
enregistrer 36
dans dautres fichiers 37
head, commande 42
less, commande 47
ligne de, conserver des parties choisies 161
lignes den-tte 43
sauter 43
ls, commande 38
-1, option 39
messages, rediriger 40, 51
vers des fichiers diffrents 40
messages.out 40
mettre en forme 34
mots rservs 45
-n, option, saut de ligne avec echo 35
noclobber, option 55
-nombre, option (head, tail), changer le
nombre de lignes 42
noms de chemins dans la redirection 37
OFS (sparateur de champs de awk) 282
oprateurs de redirection 41
printf 34
rediriger 356
avec ls -C 38
regrouper 44
rm, commande 49
sans tampon 52
saut de ligne par dafut 35
STDERR (>&2) 40
STDIN (entre standard) 52
STDOUT (sortie standard) 40, 52, 53
suppression partielle 160
tail, commande 42
tee, commande 47, 52
trie 171
tubes 47
utiliser comme entre 46
vider les donnes inutiles 44
source, commande 202, 209
sous-chane, fonction 269
sous-expressions, remplir les variables
tableaux 128
sous-shells 45
Spafford, Gene 292

Elodie FRITSCH <elodie.fritsch@total.com>

632
split, commande 345
Spotlight, moteur de recherche locale 201
SSH
certificats 70
cls
en cache, vider 326
publiques 354
commandes
dsactiver 330
forces 329
restreindre 329331
$ID_SSH 355
OpenSSH 321
OpenSSH Restricted Shell 331
prise en charge des empreintes 328
restriction dhte 330
rssh 331
sans mot de passe 321
ssh, commande, fonctionnement 331
SSH Communications Security 321
SSH, le shell scuris La rfrence
(ditions OReilly) 327
ssh -v, trouver des problmes 330
ssh -v -v, trouver des problmes 330
ssh-add, commande 325
ssh-agent 321
ssh-keygen (ssh-keygen2) 321
$UTILISATEUR_SSH 355
SSH, le shell scuris La rfrence (ditions
OReilly) 321
$STAT, variable 74
STDERR (>&2) 40, 53, 208, 256
STDIN (entre standard) 52, 208
stdio.h 403
STDOUT (sortie standard) 40, 52, 53, 208
stocker des scripts et des donnes de test avec
NFS 339
strftime 394
dfinition de format 224
fonction C (man 3 strftime), options de
format 225
_struct 402
stty sane, rparer echo 70, 496
su, commande 5, 456
substitutions, franchir les limites 479
Subversion 133, 270, 575
sudo bash 318
sudo, commande 5, 17, 456
scurit 318
sudoers 318
Sunfreeware 23
suprieur (>) 36, 38, 59
oprateur de redirection 208
rediriger la sortie 50
suprieur double (>>), oprateur 120

[05/03/08]

bash Le livre de recettes

Index
suprieur et esperluette (>&) 41
supprimer
des caractres 185
option -d (cut) pour prciser des
dlimiteurs 185
des rpertoires 377
SUSE 20
svn, commande 133
svn status, commande 270
symboliques, liens 195, 246, 386
Synaptic 20
syntaxe
portable pour $IFS 299
vrifier lexactitude 499
syslog 348, 359

T
Tab, touche 482
tableau_aide 402
tableaux
une dimension 111
associatifs (hachages en awk) 165
convertir la sortie en 264
initialisation 111, 264
variables
pour remplir 128
utiliser 111
tabulation, caractre 64, 177, 281
tches 79, 369
cron et mots de passe 321
par lot, journaliser 437
tail, commande 42
-F, option 42
-f, option 42
tampons, dbordement 293
tar, commande 178
-t, option, afficher la liste du contenu 182
tarball 178
techniques de programmation 292
tee, commande 47, 52
tlchargements pour ce livre 371
test, commande 118, 123
test, oprateurs 536
test -t, option 130
Texinfo 431, 432
texte, utilitaires de manipulation
^ (accent circonflexe), correspondre au
dbut de la ligne 158
(apostrophe), pour les recherches 157
* (astrisque) 157
\ (barre oblique inverse)
correspondre des caractres
spciaux 158
dans les recherches 157
[] (crochets simples) 158

Elodie FRITSCH <elodie.fritsch@total.com>

Index
texte, utilitaires de manipulation (suite)
$ (dollar) 158
$() (dollar et parenthses), pour les noms de
fichiers sur la ligne de
commande 152
" (guillemets), supprimer 186
. (point) dans les expression rgulires 157
!! (point dexclamation double), oprateur
pour lhistorique 155
adresses IP 173
ar, archives 180
awk, programme 149, 160, 162
BEGIN, mot-cl (awk) 164
bennes bits 153
-c, option (grep) 151
champs 176
chemins
absolus 182
relatifs 179
compression 178
algorithmes 179
bzip2 178
gzip 178
continue, instruction 168
CPIO, fichiers 180
cut, commande 176
-d, option 177
(cut), prciser des dlimiteurs 185
(tr) 185
.deb, fichiers 180
dlimiteurs 176
sans correspondance 177
/dev/nul, pour les scripts portables) 153
donnes numriques 172
END, mot-cl (awk) 164
entre de grep 151
expressions en criture seule 159
extensions 180
-f, option (awk), boucler sur une
chanes 165
-F, option (awk), dlimiter des champs 161
fichiers
compresss, passer grep 159
DOS, passer sous Linux 185
file, commande 181
fmt, commande 188
for, boucle 162
getline, commande 164
grep, commande 149
avec des fichiers compresss 159
gzcat 160
-h, option (grep) 150
histogramme 166
indicateurs, dsactiver 169
-j, pour bzip2 179

[05/03/08]

bash Le livre de recettes

633
-l, option
avec grep 151
convertir des fins de lignes en DOS 179
(ls), conserver des parties choisies de la
sortie 161
less, commande 160, 189
tendre 189
page de manuel 189
$LESS, variable 189
$LESSCLOSE 189
$LESSOPEN 189
lesspipe* 190
lesspipe.sh 190
ligne de sortie, conserver des parties
choisies 161
lignes en double, supprimer 177
-ll, option (unzip), convertir des fins de
lignes DOS 179
messages de journalisation, supprimer par
erreur 156
mots, inverser lordre 162
-n, option (sort), trier des nombres 172
NetBSD, tris stables 175
NF, variable (awk) 162
boucler sur des chanes 165
\{n,m\}, mcanisme de rptition 158
nombres, additionner une liste 163
nommage 179
noms de reprtoires, analyser 182
options 172
de grep 150
ordre de tri 175
paragraphes, reformater 188
paramtres rgionaux, pour le tri 175
phrases
chercher 168
cls 168
POSIX 174
pr, commande 188
prprocesseurs 189
pr-trier 173
-q, option (grep) 153
RE (expression rgulire) 157, 164
recherches 154, 156, 157, 158
dans un tube 154
insensibles la casse 154
mcanisme de rptition 158
vrai/faux 152
remplacer du texte 183
retour chariot (\r), supprimer 185
RPM (Red Hat Package Manager) 180
-S, option (sort) dsactiver le tri stable sur
NetBSD, fixer la taille du tampon
sinon 175

Elodie FRITSCH <elodie.fritsch@total.com>

634

Index

texte, utilitaires de manipulation (suite)


sed, programme 149
sensibilit la casse, liminer 184
sparateur de champs 174
squence dchappement 185
sort, commande 171
sortie
suppression partielle 160
variantes 150
sous-ensembles 176
-t, option (sort) 174
tableaux associatifs (hachages en awk) 165
tabulation 177
tar, commande 178, 179
-t, option, afficher la liste du
contenu 182
tarball 178
tarball.tar.gz 179
tarball.tar.Z 179
textutils 284
^total 164
tr, commande 185
pour la traduction 183
tri stable 175
-u, option (sort), supprimer les doublons lors
du tri 173
uniq, afficher les lignes en double 178
-v, option (grep), pour les recherches 156
valeur de retour 0 153
valeurs chanes, compter 164
wc, commande 187
-Z, compresser avec GNU tar 179
-z, compresser avec gzip depuis tar 179
zcat 160
zgrep 159
The GNU Bash Reference Manual pour bash
Version 2.05b 394
then (if) 117
this week, utiliser avec prudence 229
Thunderbird 361
tierces parties, bibliothques 406
tilde (~) 4, 108
tiret (-) 43, 408
afficher une ligne de 239
shell 337
tkman, afficheur et convertisseur Texinfo 432
$TMOUT, variable 331
/tmp, rpertoire temporaire 38
/tmp/ls, script malveillant 303
touche meta (mode commande de screen) 435
tr, commande 185
squence dchappements 548
trafic rseau 348
traitement de la ligne de commande,
rpter 573

[05/03/08]

bash Le livre de recettes

trap
configurer 305
utilitaire 215
Tripwire 293
tris, comparaison 175
Troie, cheval de 293
trouver
le plus ancien 121
les fichiers identiques 121
Tru64 Unix 23
Open Source Software Collection 23
tty, commande interne 401
tty, terminal de contrle 207
ttyname 403
tubes
crer des sous-shells 493
entres/sorties 47
recherche dans 154
*.txt, pour la correspondance de motifs 11
type, commande 14, 221
-a, option 6
-P, option 202
-type d, trouver des rpertoires 198
-type, prdicat de find 197

U
Ubuntu
6.10, fichiers rc douverture de session
bash 412
cut, commande 176
lesspipe 190
Linux 5.10 339
sudo 455
systmes drivs de Debian 20
tiret, utiliser 22, 334, 337, 342, 384, 417
UCLA 23
UDP 348
ulimit 298
umask fiable 299
$UMASK, variable 299
un fichier par ligne, option (ls -1) 9
unalias 385
\unalias -a, commande 296
uniq, afficher les lignes en double 178
Unix
autorisations des fichiers 312
date, commande 223
dates et heures, omettre lanne dans les
commandes 234
de type BSD 17
groupes 312
$PATH, changer 412
shell 1
de root, changer 17
UnixReview 229

Elodie FRITSCH <elodie.fritsch@total.com>

Index
Unix (suite)
versions de bash 23
Windows Services 25
unzip 256, 432
$UNZIP, variable 82
urandom 305
usage, aide abrge 402
USAGE, fonction 245
/usr, partition 17
/usr/bin/env, commande 334
usurpation, setuid root 294
utilisateur 88
documentation 88
entre de 64
inactif 331
invit, restreindre 314
nom dutilisateur@nom dhte 369
long 369
non privilgi 293
non-root 317
rpertoires de 377
usermod -s /usr/bin/bash, changer de shell
par dfaut 17
$UTILISATEUR_SSHR 355
utilitaires
infests 293
personnels 389
uuencode 360

V
-v, option 104, 361
-V, option (mkisofs) 253
valeurs
compter 164
de retour, zro 132
en vigule flottante 136
par dfaut 104, 105
${#VAR} 102
${VAR#alt} 102
${variable/motif/remplacement} 202
variables
{} (accolades) 92
$ (dollar) 86
$$ (dollar double) 253
$@ (dollar et arobase) 99
sans les guillemets 100
$*, erreurs dutilisation 99
$*, sans les guillemets 100
= (signe gal), dans les commandes 86
$0 245
$CDPATH 383
commandes, diffrencier des variables 86
$COMPREPLY 409
$COMP_WORDS 409
de type tableau 128

[05/03/08]

bash Le livre de recettes

635
galit, tester 124
env (export -p) 93
-eq, oprateur pour les comparaisons
numriques 124
erreurs dans 99
excuter des commandes depuis 81
exporter 92
FIELDWIDTHS 283
grep, commande 95
$HIST* 393
$HISTCONTROL 394
$HISTFILE 394
$HISTFILESIZE 394
$HISTIGNORE 394
$HISTSIZE 394
$HISTTIMEFORMAT 394
$INPUTRC 387
$LESS 189
MAILTO 361
modifier des valeurs exportes 93
noms 82, 85, 90, 92
nom=valeur, syntaxe 85
passage par valeur 93
$PATH 6, 72, 376, 377382
$PROMPT_COMMAND 374
$PS1 368, 372, 428
$PS2 368
$PS3 68, 142, 372, 390
$PS4 372, 392
$PWD 373
rfrences, utiliser la syntaxe complte 92
$REPLY 69
$SCRIPT 83
set, commande 94
$STAT 74
syntaxe 85
tableaux 111, 264
$TMOUT 331
$UMASK 299
$UNZIP 82
valeur-R, syntaxe 86
valeurs, afficher 94
vides 497
$ZIP 82
$VERBEUX 104
version
postscript dun fichier (.ps) 28
texte (ASCII) 28
vi 468
commandes en mode 553
et Emacs, chappement vers le shell 315
vipw, commande, vrifier la cohrence des
fichiers de mots de passe 17
virgule (,), oprateur 115
virgule flottante, valeurs en 136
visudo, pour les modifications 319

Elodie FRITSCH <elodie.fritsch@total.com>

636
VMware 338
console base sur VNC 339
VMware Player 339
VMware Server 339
vrai/faux, recherches 152

W
\w, afficher le chemin complet 373
\W, afficher le nom de base 373
Wall, Larry 431
Wang, Michael 467, 472
wc, commande 187
wdiff 445
wget 350
which, commande 6, 14, 203
while, boucle 79, 131, 133, 249
while read 132
Windows
bash 24
Cygwin 24
environnement de type Linux 24
GNU Text Utils 25
Windows Services pour UNIX 25
WORD_LIST 403
Writing Shell Scripts, documentation 28

Index
x86, architecture 339
xargs, commande 193, 357
-i, option 194
xme jour avant ou aprs celui indiqu 229
non rcursif 229
xme jour de la semaine avant ou aprs celui
indiqu 229
xme mois avant ou aprs celui indiqu 229
xpg_echo 342
xterm 370, 374
xtrace 501
invite de dbogage 372
{x..y}, expansion des accolades 471

Y
YaST 20

Z
-Z, compresser avec GNU tar 179
-z, compresser avec gzip depuis tar 179
zcat 160
zro
lment 128, 215
valeur de retour 132
zgrep 159
Zip, fichiers 256, 432
$ZIP, variable 82

$x, ne pas utiliser 90


voir aussi $i

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

propos de lauteur
Carl Albing est un programmeur Java, C et bash de longue date. Il travaille avec Linux et
Unix depuis son entre au St. Olaf College au milieu des annes 70. Auteur et enseignant, il
a donn des prsentations techniques lors de confrences et au sein dentreprises aux tatsUnis, au Canada et en Europe. Titulaire dun baccalaurat en mathmatiques et dun master
en gestion internationale, il poursuit toujours ses tudes. Il travaille aujourdhui comme ingnieur logiciel pour la socit Cray, Inc. et comme consultant indpendant. Carl est coauteur de Java Application Development on Linux (Prentice Hall PTR). Il peut tre contact via
son site web (www.carlalbing.com) ou le site dOReilly Media (www.oreilly.com) en cherchant
Albing.
JP Vossen utilise les ordinateurs depuis le dbut des annes 80 et travaille dans lindustrie
informatique depuis le dbut des annes 90. Il est spcialis dans la scurit des informations. Il se passionne pour les scripts et lautomatisation depuis quil a compris lobjectif du
fichier autoexec.bat. Il a t trs heureux de dcouvrir la puissance et la souplesse de bash et
de GNU sur Linux. Ses articles sont parus, entre autres, dans Information Security Magazine et
SearchSecurity.com. Lorsquil ne se trouve pas devant un ordinateur, ce qui est assez rare, il
est certainement en train de dmonter ou de remonter quelque chose.
Cameron Newham est un dveloppeur uvrant dans les technologies de linformation et
vivant Royaume-Uni. N en Australie, il a obtenu son diplme scientifique en technologie
de linformation et gographie luniversit dAustralie ouest. Pendant son temps libre, il
travaille sur son projet de numrisation des btiments anglais larchitecture remarquable.
Il sintresse galement diffrents domaines, comme la photographie, la science spatiale,
limagerie numrique, lecclsiologie et lhistoire de larchitecture. Il est le co-auteur du livre
Le shell bash (ditions OReilly).

Colophon
Mrement rflchie, la prsentation de nos ouvrages a t conue afin de satisfaire les exigences de nos revendeurs sans trahir les attentes du lecteur. En cela, le choix dune couverture dlibrment hors de propos tmoigne du souci permanent doffrir une approche
originale de sujets rputs austres.
Lanimal de la couverture de bash Le livre de recettes est une tortue des bois (Glyptemys insculpta). Son nom vient de sa carapace qui semble avoir t sculpte dans le bois. La tortue des
bois vit dans les forts et est trs commune en Amrique du nord, notamment en Nouvelle
cosse et dans la rgion des Grands lacs. Cette espce est omnivore et un mangeur
paresseux ; elle avale ce quelle trouve sur son chemin, quil sagisse de plantes, de vers ou de
limaces (son plat prfr). La tortue des bois nest pas un animal lent. En ralit, elle est plutt agile et apprend trs rapidement. Certains chercheurs ont vu certains spcimens frapper
le sol afin de simuler la pluie et faire ainsi sortir les vers.
La tortue des bois est menace par linvasion de son territoire par les hommes. Elles vivent
sur les berges sablonneuses des rivires, des ruisseaux et des tangs, qui sont soumises lrosion, lendiguement et aux activits de plein air. Les accidents de la route, les pollutions et
le commerce danimaux ont galement un impact ngatif sur la population des tortues des
bois, tel point que, dans certains tats et provinces, elles sont considres comme une espce en danger.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Limage de couverture provient dune gravure du 19e sicle appartenant au fond de la Dover
Picturial Archive.

Ldition franaise
La couverture de ldition franaise a t cre par Marcia Friedman.
Les polices du texte de la version franaise sont Le Monde Livre, Le Monde Sans et TheSansMonoCon.

[05/03/08]

bash Le livre de recettes

Elodie FRITSCH <elodie.fritsch@total.com>

Vous aimerez peut-être aussi