You are on page 1of 662

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

bash
Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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/

[05/03/08]

bash Le livre de recettes

oykoT iepiaT lopotsabeS nikP siraP mahnraF engoloC egdirbmaC


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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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. 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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

vi 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.

Table des matires 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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. 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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Table des matires 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. 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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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. 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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Table des matires 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. 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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Table des matires 15.11. 15.12. 15.13. 15.14. 15.15. 15.16. 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 ...................................

xi 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. 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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Table des matires 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. 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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Chapitre 1 Dbuter avec bash

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

8
man locate ; man slocate ; man find ; man ls ;

Chapitre 1 Dbuter avec bash

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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.
$ ls -a . .. $ ls -d .[!.]* .a ..toto .a .fichier_point_normal fichier_normal

.fichier_point_normal

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

12

Chapitre 1 Dbuter avec bash

$ ls -d .??* ..toto

.fichier_point_normal

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

.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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

1.6. Protger la ligne de commande


$ echo 'Un caf vaut $5?!' Un caf vaut $5?!

13

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

1.9. Faire de bash le shell par dfaut


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

17

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 Debian Sargea Debian Etcha Fedora Core 1 Fedora Core 2 Fedora Core 3 2.x dans linstallation initiale 2.05b Sans objet (SO) bash-2.05b31.i386.rpm bash-2.05b38.i386.rpm SO 2.x dans les mises jour 3.1dfsg-8 (testing & unstable) SO bash-2.05b34.i386.rpm SO SO 3.x dans linstallation initiale 3.0-12(1)-release 3.1.17(1)-release SO SO bash-3.017.i386.rpm 3.x dans les mises jour 3.00.16(1)release SO SO SO bash-3.018.i386.rpm

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

1.10. Obtenir bash pour Linux


Tableau 1-1. Versions par dfaut des distributions Linux (suite)
Distribution Fedora Core 4 Fedora Core 5 Fedora Core 6 Knoppix 3.9 & 4.0.2 Mandrake 9.2b Mandrake 10.1c Mandrake 10.2d Mandriva 2006.0e Mandriva 2007.0f OpenSUSE 10.0 OpenSUSE 10.1 OpenSUSE 10.2 SLED 10 RC3 RHEL 3.6, CentOS 3.6 RHEL 4.4, CentOS 4.4 MEPIS 3.3.1 Ubuntu 5.10g Ubuntu 6.06g Ubuntu 6.10
gh

19

2.x dans linstallation initiale SO SO SO SO bash-2.05b14mdk.i586.rpm bash-2.05b22mdk.i586.rpm SO SO SO

2.x dans les mises jour SO SO SO SO SO SO SO SO SO

3.x dans linstallation initiale bash-3.031.i386.rpm bash-3.16.2.i386.rpm bash-3.116.1.i386.rpm 3.0-15 SO SO bash-3.02mdk.i586.rpm bash-3.06mdk.i586.rpm bash-3.17mdv2007.0.i586 .rpm 3.00.16(1)release 3.1.16(1)-release bash-3.155.i586.rpm 3.1.17(1)-release SO 3.00.15(1)release 3.0-14 3.0.16(1) 3.1.17(1)-release 3.1.17(1)-release

3.x dans les mises jour SO bash-3.19.fc5.1.i386.rpm SO SO SO SO SO SO SO

SO SO SO SO bash-2.05b.0(1) SO SO SO SO SO

SO SO SO SO SO SO SO SO SO SO

3.0.17(1)-release SO SO SO SO SO SO SO SO 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

20
e.

Chapitre 1 Dbuter avec bash


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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

1.15. Obtenir bash sans linstaller


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.

25

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 four, nisseurs.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

28
bash.1 Page de manuel de bash. bashbug.1 Page de manuel de bashbug.

Chapitre 1 Dbuter avec bash

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. Scripts ladresse http://www.linuxcommand.org/writing_shell_

BASH Programming Introduction HOW-TO ladresse http://www.tldp.org/HOWTO/ Bash-Prog-Intro-HOWTO.html.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Ou encore :
$ echo 'ces ces mots $ mots sont sont vraiment spars' vraiment spars

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Chapitre 2 Sortie standard

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

36
$ echo -e 'salut\c' salut$

Chapitre 2 Sortie standard

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Chapitre 2 Sortie standard

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

2.12. Sauter len-tte dun fichier


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.

43

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

2.20. Permuter STDERR et STDOUT


$ uneCommande >mon.fichier 2>&1 $ uneCommande 2>&1 >mon.fichier

53

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Chapitre 3 Entre standard

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

66
local choix_oui="$3" local choix_non="$4" local reponse read -p "$invite" reponse [ -z "$reponse" ] && reponse="$defaut"

Chapitre 3 Entre standard

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

3.6. Attendre une rponse Oui ou Non


# 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.

67

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

4.5. Dterminer le succs dune commande


$ long & moyen & court [1] 4592 [2] 4593 $

77

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

5.2. Incorporer la documentation dans les scripts


Une description complte de l'application et de ses fonctionnalits. Peut comporter des sous-sections (cd =head2, =head3, etc.)

89

[...]

=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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

5.5. Exporter des variables


export MAVAR export NOM=valeur

93

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

5.10. Accepter des listes de paramtres contenant des espaces


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

99

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

5.11. Compter les arguments


Utilisons $@ dans notre exemple de fichiers MP3 :
for NF in "$@"

101

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Chapitre 5 Variables du shell

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

5.18. Modifier certaines parties dune chane


Voici un exemple dexcution du script avec des paramtres insuffisants :

109

$ ./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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 ${ ... } nom:dbut:longueur #nom nom#motif nom##motif nom%motif nom%%motif nom/motif/chane nom//motif/chane Action effectue Retourne la sous-chane commenant dbut et ayant la longueur indique. Retourne la longueur de la chane. Supprime le (plus court) motif partir du dbut. Supprime le (plus long) motif partir du dbut. Supprime le (plus court) motif partir de la fin. Supprime le (plus long) motif partir de la fin. Remplace la premire occurrence. 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

Chapitre 6 Logique et arithmtique

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 affectation simple multiplication division reste

Utilisation
a=b a*=b a/=b a%=b

Signification
a=b a=(a*b) a=(a/b) a=(a%b)

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

6.1. Utiliser larithmtique dans un script


Tableau 6-1. Les oprateurs daffectation de bash (suite)
Oprateur
+= -= <<= >>= &= ^= |=

115

Opration en plus de laffectation addition soustraction dcalage dun bit gauche dcalage dun bit droite Et binaire Ou exclusif binaire Ou binaire

Utilisation
a+=b a-=b a<<=b a>>=b a&=b a^=b a|=b

Signification
a=(a+b) a=(a-b) a=(a<<b) a=(a>>b) a=(a&b) a=(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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 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"

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

6.2. Conditionner lexcution du code


exit 2 else printf "%b" "Nombre darguments correct. Traitement en cours...\n" fi

117

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

118
echo chec; fi pwd $ bash ./essayerCeci.sh /tmp ... $ bash ./essayerCeci.sh /inexistant ... $

Chapitre 6 Logique et arithmtique

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

6.3. Tester les caractristiques des fichiers


FICHIER1 -ot FICHIER2 Est plus ancien que.

121

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
-b -c -d -e -f -g -h -G -k -L -O -p -r -s -S -u -w -x

Description Le fichier est un priphrique en mode bloc (comme /dev/hda1). Le fichier est un priphrique en mode caractre (comme /dev/tty). Le fichier est un rpertoire. Le fichier existe. Le fichier est un fichier normal. Le bit SGID (set group ID) du fichier est positionn. Le fichier est un lien symbolique (identique -L). Le fichier appartient lidentifiant de groupe rel. Le bit sticky du fichier est positionn. Le fichier est un lien symbolique (identique -h). Le fichier appartient lidentifiant dutilisateur rel. Le fichier est un tube nomm. Le fichier peut tre lu. Le fichier nest pas vide (sa taille est suprieure zro). Le fichier est une socket. Le bit SUID (set user ID) du fichier est positionn. Le fichier peut tre modifi. 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

6.6. Tester lgalit


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

125

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
-lt -le -gt -ge -eq -ne

Chane
< <= > >=

Signification Infrieur . Infrieur ou gal . Suprieur . Suprieur ou gal . gal . 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 $ 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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

138
Voici linstruction if/then/else quivalente :

Chapitre 6 Logique et arithmtique

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

148
La rponse est : 9 $ calc 2 + 3 + 4.5 La rponse est : 9.5

Chapitre 6 Logique et arithmtique

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

7.2. Garder uniquement les noms de fichiers


$ 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]); $

151

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

152
$ grep -l printf *.c both.c good.c somio.c

Chapitre 7 Outils shell intermdiaires I

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

7.15. Afficher les donnes sous forme dhistogramme


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"; } }

167

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

8.3. Trier des adresses IP


$ sort -n nombres.txt 2 21 200 250 $

173

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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)
10.0.0.2 192.168.0.2 10.0.0.4 192.168.0.4 192.168.0.12 10.0.0.20 # # # # # # sluggish laptop mainframe office speedy lanyard

NetBSD (par dfaut)


192.168.0.2 10.0.0.2 192.168.0.4 10.0.0.4 192.168.0.12 10.0.0.20 # # # # # # 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 ./monappli_1.0.1 Mauvais monappli.c monappli.h monappli.man /usr/local/bin

./bintools

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 .tar .tar.gz, .tgz .tar.bz2 .tar.Z .zip Commandes tar tf (liste le contenu), tar xf (extrait) GNU tar : tar tzf (liste le contenu), tar xzf (extrait) ou : gunzip fichier && tar xf fichier GNU tar : tar tjf (liste le contenu), tar xjf (extrait) ou : gunzip2 fichier && tar xf fichier GNU tar : tar tZf (liste le contenu), tar xZf (extrait) ou : uncompress fichier && tar xf fichier 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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
\ooo \\ \a \b \f \n

Signification Caractre dont la valeur octale est ooo Un caractre barre oblique inverse (chappement de la barre oblique inverse elle-mme) Bip audible , le caractre ASCII BEL ( b est dj occup par la suppression arrire) Suppression arrire (correction du dernier caractre) Saut de page Passage la ligne

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

186

Chapitre 8 Outils shell intermdiaires II

Tableau 8-4. Les squences d'chappement de l'outil tr


Squence
\r \t \v

Signification Retour-chariot Tabulation horizontale 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 b c d p f l s D 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

9.10. Retrouver rapidement des fichiers ou du contenu


$ 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

201

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

9.11. Retrouver un fichier partir dune liste demplacements possibles


$ command -v ls /bin/ls $ command -v cat /bin/cat $ command -v ll alias ll='ls -l'

205

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

10.2. Rutiliser du code


FORMAT_IMAGE=png FORMAT_AUDIO=ogg $

209

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 ] }

fichier1 ... fichiern\n" $0

> &2

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 ] }

fichier1 ... fichiern\n" $0

> &2

function utilisation { printf "usage : %s [ -a | - b ] }

fichier1 ... fichiern\n" $0

> &2

usage () { printf "usage : %s [ -a | - b ] }

fichier1 ... fichiern\n" $0

> &2

utilisation () { printf "usage : %s [ -a | - b ] }

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 ] } > &2

fichier1 ... fichiern\n" $0

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

2) 6) 10) 14)

SIGINT SIGABRT SIGBUS SIGALRM

3) 7) 11) 15)

SIGQUIT SIGEMT SIGSEGV SIGTERM

4) 8) 12) 16)

SIGILL SIGFPE SIGSYS SIGURG

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

216
17) 21) 25) 29) SIGSTOP SIGTTIN SIGXFSZ SIGINFO 18) 22) 26) 30)

Chapitre 10 Autres fonctionnalits pour les scripts


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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

10.6. Intercepter les signaux


$ kill %1 Je suis mort ! 0 [1]+ Terminated

217

./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 $ bg [1]+ ./dur_a_tuer &

./dur_a_tuer

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

222
else builtin cd $1 fi }

Chapitre 10 Autres fonctionnalits pour les scripts

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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' # 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 # %T quivaut %H:%M:%S

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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" ;; *) esac done DATE_FIN=$(date -d "$DATE_DEBUT +7 days" '+%Y-%m-%d') echo "DATE_DEBUT: $DATE_DEBUT" echo "DATE_FIN: $DATE_FIN" printf "%b" "Date invalide, veuillez recommencer...\n" ;;

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

228
$ 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

Chapitre 11 Dates et heures

$ 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

11.5. Convertir des secondes depuis lorigine en dates et heures


# Lheure indique est une heure UTC. $ perl -e 'use Time::Local; print timegm("49", "59", "06", "05", "10", "105") . qq(\n);' 1131173989

231

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 $ perl -e "print scalar(localtime($ORIGINE)), qq(\n);" Sat Nov 5 01:59:49 2005 # UTC

# Lheure locale.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 "Date errone : "Origine errone : "Correction : "Origine valide : "Date valide : $date_erronee" $origine_erronee" +$CORRECTION" $origine_correcte" $date_correcte"

# GNU Date.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

234
echo "Date valide ISO : $date_correcte_iso"

Chapitre 11 Dates et heures

# 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 60 300 600 3 600 18 000 36 000 86 400 172 800 604 800 1 209 600 2 592 000 31 536 000 Minutes 1 5 10 60 300 600 1 440 2 880 10 080 20 160 43 200 525 600 1 5 10 24 48 168 336 720 8 760 1 2 7 14 30 365 Heures Jours

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 Deuxime Troisime Quatrime Cinquime (voir lavertissement) Plages de jours 17 8 14 15 21 22 27 28 31

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

11.9. Utiliser date et cron pour excuter un script au nme jour


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

237

Voir aussi
man 5 crontab ; man cal.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

240
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 exit 2 } >&2

Chapitre 12 Tches utilisateur sous forme de scripts shell

LONGUEUR=72 CARACTERE='-' while (( $# > 0 )) do case $1 in [0-9]*) LONGUEUR=$1;; -c) shift CARACTERE=$1;; *) utiliserquitter;; esac shift done if (( LONGUEUR > 4096 )) then echo "trop long" >&2 exit 3 fi # 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

12.2. Prsenter des photos dans un album


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

245

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

12.3. Charger votre lecteur MP3


Linvocation du script est simple :
$ charger_mp3

249

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

255

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 ;; 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" "$*" rduire

261

\n" $OPTARG $(basename $0)

$(basename $0)

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

13.5. Analyser la sortie avec une fonction


declare -a MONTAB MONTAB=($(ls -ld $1))

265

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

13.9. Analyser une chane caractre par caractre


4 cheval fougueux 5 ne gris $ 1 2 3 4 5 $ ./auPluriel < fichier.entree poule canards oie blanches cheval fougueuxs ne griss

269

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 $ awk Ligne Ligne Ligne Ligne Ligne fichier_donnees 1 termine 2 termine 3 termine 4 termine 5 termine '{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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

13.14. Supprimer les espaces


# 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.~~

279

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 -r ligne; do toutes les espaces. : ~~$ligne~~" les espaces de dbut. : ~~${ligne##+([[:space:]])}~~"

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

13.15. Compacter les espaces


# 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

281

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' Intitule1 Intitule2 Intitule3 Enr1_Champ1 Enr1_Champ2 Enr1_Champ3 Enr2_Champ1 Enr2_Champ2 Enr2_Champ3 Enr3_Champ1 Enr3_Champ2 Enr3_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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 Intitule1 Intitule2 Intitule3 Enr1 Champ1 Enr1 Champ2 Enr1 Champ3 Enr2 Champ1 Enr2 Champ2 Enr2 Champ3 Enr3 Champ1 Enr3 Champ2 Enr3 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 Champ1 Enr1 Champ2 Enr1 Champ3 Enr2 Champ1 Enr2 Champ2 Enr2 Champ3 Enr3 Champ1 Enr3 Champ2 Enr3 Champ3

$ gawk ' BEGIN { FIELDWIDTHS = "18 32 16"; OFS = "\t" } { $1 = $1; gsub(/ +\t/, "\t"); gsub(/ +$/, ""); print }' fichier_longueur_fixe | hexdump -C

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

284
00000000 00000010 00000020 00000030 00000040 00000050 00000060 00000070 00000080 00000090 000000a0 000000b0 000000b1 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

Chapitre 13 Analyses et tches similaires


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 Champ1 Enr1 Champ2 Enr1 Champ3 Enr2 Champ1 Enr2 Champ2 Enr2 Champ3 Enr3 Champ1 Enr3 Champ2 Enr3 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 dif. ficult. 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

14.3. Dfinir une variable $PATH sre


# 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

295

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

296
'SunOS') _cut='/usr/bin/cut' _nice='/usr/bin/nice' # [...] ;; # [...] esac

Chapitre 14 Scripts scuriss

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

14.8. Dfinir un umask sr


# Dfinir un IFS sr (cette syntaxe est celle de bash et de ksh93, # elle n'est pas portable). IFS=$' \t\n'

299

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

14.9. Trouver les rpertoires modifiables mentionns dans $PATH


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

301

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

14.11. Utiliser des fichiers temporaires scuriss


mkdir -p -m 0700 $rep_temp \ || ( echo "FATAL : impossible de crer le rpertoire temporaire" \ "'$rep_temp' : $?"; exit 100 )

305

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

14.11. Utiliser des fichiers temporaires scuriss


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 # Tout dabord, essayer mktemp. NOM_TEMP=$(mktemp $type_temp ${prefixe}.XXXXXXXXX)

307

Modifiable -w $NOM_TEMP

Modifiable -w $NOM_TEMP

! Prciser

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

14.14. Afficher les mots de passe dans la liste des processus


$ 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

311

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

$ 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

21:34 21:34 21:34 21:34

fichier_sgid fichier_suid rep_sgid rep_suid

$ [ -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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

14.21. Utiliser SSH sans mot de passe


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

325

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 ? S 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

15.4. Tester des scripts sous VMware


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.

339

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

15.5. crire des boucles portables


0 1 2 3 4 5 6 7 8 9

341

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

15.6. crire une commande echo portable


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" un deux trois $ /bin/echo -e "un\tdeux\ntrois" un deux trois

343

$ shopt -s xpg_echo $ builtin echo "un\tdeux\ntrois" un deux 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" un deux trois

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

344
$ /bin/sh $ echo "un\tdeux\ntrois" un\tdeux\ntrois\n $ echo -e "un\tdeux\ntrois" un deux trois $ printf "%b" "un\tdeux\ntrois" un deux trois

Chapitre 15 Scripts labors

Solaris 10 (/bin/sh) :
$ which echo /usr/bin/echo $ type echo echo is a shell builtin $ echo "un\tdeux\ntrois" deux un trois $ echo -e "un\tdeux\ntrois" -e un deux trois $ printf "%b" "un\tdeux\ntrois" un deux 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

346
-C|--line-bytes) option_wc='-L';; -l|--lines) option_wc='-l';; esac

Chapitre 15 Scripts labors

# 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 -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..|

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 $ 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 -x 4c09 6769 694c 6e67 2020 2020 2020 2020 2020 3620 656e 3620 2020 0939 656e 2065 3420 0935 0a09 200a 000a 3120 0a32 4c09 694c 2020 2020 200a 2020 6769 6e67 2020 2020

od 31 09 0a 20 20 67 20

-tx1 09 4c 4c 69 20 20 20 20 20 20 6e 65 20 20

69 67 20 20 20 20 39

67 6e 20 20 36 36 09

6e 65 20 35 09 0a 0a

65 20 34 09 0a 20

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

15.10. Dterminer mon adresse


echo "<133>$0[$$]: Test de message syslog depuis bash" > /dev/udp/loghost.exemple.fr/514

349

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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) 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)

sit0

# NetBSD $ /sbin/ifconfig -a pcn0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 address: 00:0c:29:31:eb:19

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

15.10. Dterminer mon adresse


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

353

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 Solaris (8, 9, 10) NetBSD 2.0.2, OpenBSD 3.7, OS/X Linux (Red Hat, Debian, Ubuntu) FreeBSD 5.4 ARG_MAX (octets) 2 048 000 1 048 320 262 144 131 072 65 536

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

364
case $phase in

Chapitre 15 Scripts labors

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 # Faire retentir la sonnerie.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.2. Personnaliser linvite


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 $

369

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

370
/tmp$ ls -lar /etc > /dev/null & [1] 96461 [jp@freebsd jobs:1] /tmp$ [1]+ Exit 1 [jp@freebsd jobs:0] /tmp$

Chapitre 16 Configurer bash

ls -lar /etc >/dev/null

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.2. Personnaliser linvite


$ export PS3='Faites votre choix : ' $ select item in 'un deux trois'; do echo $item; done 1) un deux trois Faites votre choix : ^C

373

$ 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

374
# Indicateur de troncation : local symbole_tronc='...' # Variable temporaire pour PWD. local monPWD=$PWD

Chapitre 16 Configurer bash

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.2. Personnaliser linvite


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

375

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

378
# 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="

Chapitre 16 Configurer bash

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.4. Modifier temporairement $PATH


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

379

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

380
PATH=${PATH//$repertoire/}

Chapitre 16 Configurer bash

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.4. Modifier temporairement $PATH


*:$cible:* ) return 1;; * ) return 0;; esac } # Fin de la fonction contient.

381

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.8. Ajuster le comportement de readline en utilisant .inputrc


emplacement physique, votre langue ou dautres facteurs.

387

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.10. Utiliser les invites secondaires : $PS2, $PS3 et $PS4


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

391

$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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.12. Fixer les options de lhistorique du shell


4 history

395

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.13. Concevoir une meilleure commande cd


# 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.

397

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

402
struct builtin nom_commande_struct = { "nom_commande", nom_fonction, BUILTIN_ENABLED, tablea_aide, "usage", 0 };

Chapitre 16 Configurer bash

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.16. tendre bash avec des commandes internes chargeables


} list = loptend; t = ttyname (0); if (sflag == 0) puts (t ? t : "non un tty"); return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE); }

403

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 "config.h" <stdio.h> "builtins.h" "shell.h"

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

404
#include "bashgetopt.h"

Chapitre 16 Configurer bash

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 SunOS 4 SunOS 5 SVR4, SVR4.2, Irix AIX Linux NetBSD, FreeBSD Commandes
cc -pic -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c ld -assert pure-text -o tty tty.o cc -K pic -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c cc -dy -z text -G -i -h tty -o tty tty.o cc -K PIC -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c ld -dy -z text -G -h tty -o tty tty.o cc -K -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c ld -bdynamic -bnoentry -bexpall -G -o tty tty.o cc -fPIC -Iarchive -Iarchive/builtins -Iarchive/lib -c tty.c ld -shared -o tty tty.o 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.18. Utiliser correctement les fichiers dinitialisation


Tableau 16-2. Fichiers rc de bash sous Ubuntu 6.10 et Fedora Core 5
Shell interactif douverture de session Ubuntu 6.10 : /etc/profile /etc/bash.bashrc ~/.bash_profilea ~/.bashrc /etc/bash_completion 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 Shell interactif non douverture de session (bash) Ubuntu 6.10 : /etc/bash.bashrc ~/.bashrc /etc/bash_completion Fedora Core 5 : Fedora Core 5 : SO (Script) shell non interactif (/dev/null de bash) Ubuntu 6.10 : Sans objet (SO)

413

Non interactif (bash -c :) Ubuntu 6.10 : SO

Fedora Core 5 : SO

~/.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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

interactif" \ >> ~/rc.log ;; non interactif" \ >> ~/rc.log ;;

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.20. Commencer une configuration personnalise


# Raliser des oprations case $HOSTNAME in *.societe.fr ) # ;; hote1.* ) # ;; hote2.societe.fr ) # ;; drake.* ) # ;; esac propres au site ou la machine. source $CONFIGURATIONS/societe.fr contenu pour hote1. source .bashrc.hote2 echo DRAKE dans bash_profile.jp !

419

# # # #

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.20. Commencer une configuration personnalise


# 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

421

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

424
# Fonctions utiles.

Chapitre 16 Configurer bash

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

16.20. Commencer une configuration personnalise


#!/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.

427

# 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

17.8. Capturer les mta-informations des fichiers pour une restauration


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

439

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

17.10. Utiliser diff et patch


@@ -1,2 +0,0 @@ -Ce fichier n'est que dans le rpertoire d'origine. -Il comporte deux ligne dont celle-ci est la dernire.

443

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

17.11. Compter les diffrences dans des fichiers


$ 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.

447

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

17.16. Trouver les lignes prsentes dans un fichier mais pas dans un autre
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

457

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

17.16. Trouver les lignes prsentes dans un fichier mais pas dans un autre
$ grep -vf droit gauche enregistrement_03 enregistrement_06 enregistrement_09

459

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 $ ps aux | grep '[s]sh' root 366 0.0 1.2 340 root 25358 0.0 1.9 472 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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 bulation 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"

indique une ta-

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

17.22. crire des squences


2 ligne 2 3 4 ligne 4 5 ligne 5 6

469

$ 1 2 3 4 5 6

awk '{ print NR, $0 }' nom_fichier ligne 1 ligne 2 ligne 4 ligne 5

$ perl -ne 1 ligne 2 ligne 3 4 ligne 5 ligne 6

'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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 $ a b c d e Bash 3.0+ uniquement, entiers ou caractres printf "%s texte\n" {1..5} texte texte texte texte texte 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

494
# ... done echo $COMPTEUR

Chapitre 19 Bourdes du dbutant

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

19.8. Oublier que les tubes crent des sous-shells


done echo $COMPTEUR )

495

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

498
$ bash scriptBizarre noeuds corrects : 0 noeuds invalides : 6 noeuds manquants : 0 CORRECTS=6 INVALIDES=0 MANQUANTS=0 $ $ cat scriptBizarre #!/bin/bash invalides=6

Chapitre 19 Bourdes du dbutant

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

500
$ bash -n monScript $ $ echo 'echo "Ligne invalide' >> monScript

Chapitre 19 Bourdes du dbutant

$ 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

19.13. Dboguer des scripts


resultat=$1 [ $resultat = 1 ] \ && { echo "Votre rsultat est 1 ; excellent." ; exit 0; } \ || { echo "Vous avez chou, disparaissez ! " ; exit 120; }

501

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

504
complete -G et compgen -G ; complete -X et compgen -X ;

Chapitre 19 Bourdes du dbutant

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 -c chane Signification Les commandes sont lues depuis chane. Les arguments placs aprs chane sont interprts comme des paramtres positionnels, en commenant $0. 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. 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. bash se comporte comme sil avait t invoqu en tant que shell douverture de session. Attend les mmes arguments que set -o.

-D

-i

-l -o option

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

506

Annexe A Listes de rfrence

Tableau A-1. Options de la ligne de commande de bash (suite)


Option -O, +O option-shopt Signification 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. 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). Le shell fonctionne en mode restreint. 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 -. 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. Identique -D. Identique -D, mais la sortie est au format de fichier dobjet portable (po) de GNU gettext. Affiche un message dutilisation et se termine. bash se comporte comme sil avait t invoqu en tant que shell douverture de session. Identique -l. La bibliothque readline de GNU nest pas utilise pour lire les lignes de commandes en mode interactif. Le fichier de dmarrage /etc/profile nest pas lu, tout comme les fichiers dinitialisation personnels. 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. Le comportement de bash suit plus troitement la norme POSIX l o son fonctionnement par dfaut est diffrent. Aucune information nest affiche au dmarrage du shell. Il sagit du comportement par dfaut. En mode interactif, bash excute les commandes lues depuis fichier la place du fichier dinitialisation ~/.bashrc. quivalent -v. Affiche le numro de version de cette instance de bash et se termine.

-s

-r -v --

--debugger

--dump-strings --dump-po-strings --help --login --noediting --noprofile --norc

--posix --quiet --rcfile fichier, --init-file fichier --verbose --version

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 \a \A \d \D {format} Signification Le caractre ASCII de la sonnerie (007). Lheure actuelle au format HH:MM sur 24 heures. La date au format Jour-de-la-semaine Mois Jour . 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. Le caractre ASCII dchappement (033). Le nom dhte. Le nom dhte jusquau premier . . Le nombre de tches actuellement gres par le shell. Un retour chariot et un saut de ligne. Un retour chariot. Le nom du shell. Lheure actuelle au format HH:MM:SS sur 12 heures. Lheure actuelle au format HH:MM:SS. Lheure actuelle au format a.m./p.m. sur 12 heures. Le nom de lutilisateur courant. Le numro de version de bash (par exemple, 2.00). bash-1.14.7 Le numro de version complet de bash ; la version et bash-1.14.7 le niveau de correctif (par exemple, 3.00.0). Le rpertoire de travail. 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 $. 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. bash-1.14.7 bash-1.14.7 bash-2.01.1 bash-2.03 La base du nom du priphrique de terminal du shell. bash-2.03 bash-1.14.7 bash-1.14.7 Disponibilit bash-1.14.7 bash-2.05

\e \H \h \j \l \n \r \s \T \t \@ \u \v \V \w \W \# \! \$ \nnn \\ \[ \]

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 0 1 2 4 5 7 8 Attribut de caractre Rinitialisation Clair Fonc Soulign Clignotant Invers Masqu Code Couleur Code Couleur davant-plan davant-plan darrire-plan darrire-plan 30 31 32 33 34 35 36 37 Noir Rouge Vert Jaune Bleu Magenta Cyan Blanc 40 41 42 43 44 45 46 47 Noir Rouge Vert Jaune Bleu Magenta Cyan 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 ! : . alias bg bind break builtin case cd command compgen complete R Type R 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. Dfinir un raccourci pour une commande ou une ligne de commande. Placer la tche en arrire-plan. Lier une squence de touches une fonction ou une macro readline. Quitter la boucle for, select, while ou until englobante. Excuter la commande interne indique. Construction conditionnelle choix multiples. Changer de rpertoire de travail. Excuter une commande en contournant la recherche des fonctions. Gnrer les compltions possibles. Prciser le fonctionnement de la compltion.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Commandes internes et mots rservs


Tableau A-4. Commandes internes et mots rservs (suite)
Commande continue declare dirs disown do done echo elif else enable esac eval exec exit export fc fg fi for function getopts hash help history if in jobs kill let local logout popd pushd pwd R R R R R R R R R R Type Description

509

Passer litration suivante de la boucle for, select, while ou until. Dclarer des variables et leur donner des attributs. Identique typeset. Afficher la liste des rpertoires actuellement mmoriss. Supprimer une tche du tableau de tches. lment dune construction for, select, while ou until. lment dune construction for, select, while ou until. Afficher les arguments. lment dune construction if. lment dune construction if. Activer et dsactiver des commandes internes. Fin dune construction case. Passer les arguments indiqus au traitement de la ligne de commande. Remplacer le shell par le programme indiqu. Quitter le shell. Crer des variables denvironnement. Corriger une commande (modifier le fichier dhistorique). Passer une tche au premier plan. lment dune construction if. Construction de boucle. Dfinir une fonction. Traiter les options de la ligne de commande. Les noms de chemins complets sont dtermins et mmoriss. Afficher des informations sur des commandes internes. Afficher lhistorique des commandes. Construction conditionnelle. lment dune construction case. Afficher les tches en arrire-plan. Envoyer un signal un processus. Affecter des variables arithmtiques. Crer une variable locale. Quitter un shell douverture de session. Retirer un rpertoire de la pile. Ajouter un rpertoire la pile. Afficher le rpertoire de travail.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

510
Tableau A-4. Commandes internes et mots rservs (suite)
Commande read readonly return select set shift suspend test then time R R R Type Description

Annexe A Listes de rfrence

Lire une ligne depuis lentre standard. Dfinir des variables en lecture seule (non modifiables). Sortir de la fonction ou du script englobant. Construction de menus. Fixer des options. Dcaler les arguments de la ligne de commande. Suspendre lexcution dun shell. valuer une expression conditionnelle. lment dune construction if. Excuter un tube de commandes et afficher la dure de lexcution. Le format de la sortie peut tre dfini dans la variable TIMEFORMAT. Afficher le cumul des temps utilisateur et systme pour les processus excuts partir du shell. Dfinir un gestionnaire de signal. Identifier la source dune commande. Dclarer des variables et leur donner des attributs. Identique declare. Fixer/afficher les limites de ressources de processus. Fixer/afficher le masque des autorisations de fichiers. Supprimer les dfinitions dalias. Supprimer les dfinitions de variables ou de fonctions. R R Construction de boucle. Attendre la fin dune ou plusieurs tches en arrire-plan. Construction de boucle.

times trap type typeset ulimit umask unalias unset until wait while

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Variables internes
Tableau A-5. Variables denvironnement internes au shell
Variable * Type R Description

511

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.

# ? _ $ ! 0 BASH BASH_ARGC

R R R R R R R

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. 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. 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. Largument de loption dinvocation -c. Le nom dun fichier dfinissant lenvironnement excuter lors de linvocation du shell.

BASH_ARGV

BASH_COMMAND

BASH_EXECUTION_ STRING BASH_ENV BASH_LINENO T

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]}.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

512

Annexe A Listes de rfrence

Tableau A-5. Variables denvironnement internes au shell (suite)


Variable BASH_REMATCH Type RT 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. 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. Le numro de version de cette instance de bash. RT Les informations de version de cette instance de bash. Chaque lment du tableau dtient une partie du numro de version. Une liste des rpertoires recherchs par la commande cd. 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. 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. 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. U 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. Le contenu actuel de la pile de rpertoires. Lidentifiant dutilisateur rel de lutilisateur connect.

BASH_SOURCE BASH_SUBSHELL

BASH_VERSION BASH_VERSINFO

CDPATH COMP_CWORD

COMP_LINE

COMP_POINT

COMP_WORDBREAKS

COMP_WORDS

COMPREPLY DIRSTACK EUID

T RTU R

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Variables internes
Tableau A-5. Variables denvironnement internes au shell (suite)
Variable FUNCNAME Type RTU Description

513

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. La liste des noms ignorer lors de la compltion des noms de fichiers. La liste des motifs dfinissant les noms de fichiers ignorer lors de lexpansion des noms de chemins. 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.

FCEDIT FIGNORE GLOBIGNORE GROUPS IFS L L RT

HISTCMD HISTCONTROL

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). Le nom du fichier dhistorique des commandes. Une liste de motifs qui dterminent ce qui entre dans lhistorique. Le nombre de lignes conserves dans lhistorique des commandes. Le nombre maximum de lignes conserves dans le fichier dhistorique. 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. Le rpertoire personnel (daccueil). Le fichier utilis pour la compltion des noms dhtes.

HISTFILE HISTIGNORE HISTSIZE HISTFILESIZE HISTTIMEFORMAT

HOME HOSTFILE

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

514

Annexe A Listes de rfrence

Tableau A-5. Variables denvironnement internes au shell (suite)


Variable HOSTNAME HOSTTYPE IGNOREEOF INPUTRC LANG Type Description Le nom de lhte courant. Le type de machine sur laquelle sexcute bash. Le nombre de caractres EOF reus avant de clore un shell interactif. Le fichier de dmarrage de readline. 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. Dtermine les paramtres rgionaux servant la traduction des chanes entre guillemets prcdes dun symbole $. Dtermine les paramtres rgionaux servant la mise en forme des nombres. U Le numro de la ligne qui vient dtre excute dans un script ou une fonction. Une chane qui dcrit le systme sur lequel bash sexcute. Le nom du fichier consulter pour dterminer larrive dun nouveau message lectronique. Lintervalle (en secondes) de vrification de larrive dun nouveau message lectronique. L La liste des noms de fichiers consulter pour dterminer larrive dun nouveau message lectronique, si $MAIL nest pas dfinie. Le rpertoire de travail prcdent. La valeur du dernier argument doption trait par getopts. Si elle vaut 1, les messages derreur de getopts sont affichs. Le numro du premier argument aprs les options. Le systme dexploitation sur lequel bash sexcute. L T Le chemin de recherche des commandes. Une variable tableau contenant la liste des codes de sortie des processus impliqus dans le dernier tube excut au premier plan.

LC_ALL LC_COLLATE LC_CTYPE

LC_MESSAGES LC_NUMERIC LINENO MACHTYPE MAIL MAILCHECK MAILPATH

OLDPWD OPTARG OPTERR OPTIND OSTYPE PATH PIPESTATUS

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Variables internes
Tableau A-5. Variables denvironnement internes au shell (suite)
Variable POSIXLY_CORRECT Type Description

515

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. Sa valeur est excute comme une commande avant laffichage de linvite principale. La chane de linvite principale. La chane de linvite pour les continuations de ligne. La chane de linvite de la commande select. La chane de linvite de loption xtrace. R U Lidentifiant du processus parent. Le rpertoire de travail. 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. U Le nombre de secondes coules depuis linvocation du shell. Le nom de chemin complet du shell. LR La liste des options du shell actives. 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. Prcise le format de sortie du mot rserv time dans un tube de commandes. Fixe un entier positif, elle indique le nombre de secondes aprs lequel le shell se termine automatiquement en labsence de saisie. R Lidentifiant de lutilisateur courant. Dtermine le fonctionnement du contrle des tches (les valeurs sont exact, substring ou autre chose que ces motscls). Prcise les caractres de contrle de lhistorique. Par dfaut, il sagit de la chane !^#.

PROMPT_COMMAND PS1 PS2 PS3 PS4 PPID PWD RANDOM REPLY

SECONDS SHELL SHELLOPTS SHLVL

TIMEFORMAT TMOUT

UID auto_resume

histchars

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 -a -B -b -C -E Nom complet (-o) allexport braceexpand notify noclobber errtrace Signification Exporter toutes les variables dfinies ou modifies par la suite. Le shell effectue lexpansion des crochets. Elle est active par dfaut. Afficher immdiatement le code de sortie des tches darrire-plan qui se terminent. Interdire le remplacement des fichiers existants par la redirection. Toute capture de ERR est hrite par les fonctions shell, les substitutions de commandes et les commandes excutes dans un sous-shell. 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 !. Utiliser ldition de la ligne de commande de type Emacs. Dsactiver lexpansion du nom de chemin. Activer la substitution dhistorique avec !. Elle est active par dfaut dans les shells interactifs. Activer lhistorique des commandes. Elle est active par dfaut dans les shells interactifs. Activer le hachage des commandes. Interdire la sortie du shell par Ctrl-D. 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. Activer le contrle des tches. Elle est active par dfaut dans les shells interactifs. Lire des commandes et vrifier leur syntaxe, mais ne pas les excuter. Elle est ignore dans les shells interactifs.

-e

errexit

emacs -f -H noglob histexpand history -h -k hashall ignoreeof keyword

-m -n

monitor noexec

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Options de shopt
Tableau A-6. Options de set (suite)
Option -P Nom complet (-o) physical Signification

517

Ne pas suivre les liens symboliques dans les commandes qui changent le rpertoire de travail. Utiliser le rpertoire physique. Le script sexcute en mode privilgi (suid). 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. Changer le comportement afin quil se conforme la norme POSIX 1003.2 l o ce nest pas le cas par dfaut. Toute capture de DEBUG est hrite par les fonctions shell, les substitutions de commandes et les commandes excutes dans un sous-shell. Quitter aprs avoir lu et excut une commande. Considrer les variables non dfinies comme des erreurs et non comme nulles. Afficher les lignes dentre du shell avant de les excuter. Utiliser ldition de la ligne de commande de type vi. Afficher les commandes, aprs les expansions, avant de les excuter. 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 -).

-p

privileged pipefail

posix -T functrace

-t -u -v -x -

onecmd nounset verbose vi xtrace

--

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

518
Tableau A-7. Options de shopt
Option cdable_vars Signification si dfinie

Annexe A Listes de rfrence

Lorsquun argument de cd nest pas un rpertoire, il est considr comme un nom de variable qui contient le rpertoire cible. 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. 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. Vrifier la taille de la fentre aprs chaque commande et, si elle a chang, actualiser les variables $LINES et $COLUMNS en consquence. Tenter denregistrer toutes les lignes dune commande sur plusieurs lignes dans une mme entre de lhistorique. Les noms de fichiers qui commencent par un . sont pris en compte lors de lexpansion du nom de chemin. 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. Les alias sont dvelopps. 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. 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. 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. Les messages derreurs du shell sont affichs en respectant le format standard de GNU. Lhistorique est ajout au fichier indiqu par la valeur de la variable $HISTFILE lorsque le shell se termine, au lieu dcraser le fichier.

cdspell

checkhash

checkwinsize

cmdhist dotglob execfail

expand_aliases extdebug

extglob failglob

force_fignore

gnu_errfmt histappend

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Options de shopt
Tableau A-7. Options de shopt (suite)
Option histreedit histverify Signification si dfinie

519

Si readline est utilise, il est possible de remodifier une substitution dhistorique qui a chou. 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. Si readline est utilise, une compltion de nom dhte sera tente lorsquun mot commence par @. bash envoie SIGHUP toutes les tches lors de la terminaison dun shell douverture de session interactif. Accepter les mots commenant par #, en ignorant tous les caractres suivants de la ligne, dans 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. Indique que bash a t dmarr comme un shell douverture de session. Cette valeur est en lecture seule. 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. Si readline est utilise, la variable PATH nest pas consulte pour trouver les compltions possibles lorsque la ligne est vide. La compilation des noms de chemins se fait de manire insensible la casse. Les motifs qui ne correspondent aucun fichier sont remplacs par des chanes nulles et non par eux-mmes. Les outils de compltion programmable sont activs. Cest le cas par dfaut. Les chanes dinvite sont sujettes lexpansion des variables et des paramtres aprs avoir t dveloppes. Indique si le shell a t dmarr en mode restreint. Cette valeur est en lecture seule. La commande interne shift affiche une erreur lorsque le dcalage dpasse le dernier paramtre positionnel. La commande interne source utilise la valeur de $PATH pour trouver le rpertoire qui contient le fichier fourni en argument. echo dveloppe par dfaut les squences dchappement base de barre oblique inverse.

hostcomplete huponexit interactive_comments lithist

login_shell mailwarn

no_empty_cmd_completion

nocaseglob nullglob progcomp promptvars restricted_shell shift_verbose sourcepath

xpg_echo

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables
Variable denvironnement 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. 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. 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. U 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. T T L 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. COMP_CWORD Type var. denv.

[05/03/08]

Option de set

Nom complet de set

Option de shopt

COMP_LINE

COMP_POINT

Ajuster le comportement du shell avec set, shopt et les variables

COMP_WORDBREAKS

COMP_WORDS

COMPREPLY FIGNORE

521

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description 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. Si readline est utilise, une compltion de nom dhte sera tente lorsquun mot commence par @. HOSTFILE Le fichier utilis pour la compltion des noms dhtes. Si readline est utilise, la variable PATH nest pas consulte pour trouver les compltions possibles lorsque la ligne est vide. Les outils de compltion programmable sont activs. Cest le cas par dfaut. INPUTRC Le fichier de dmarrage de readline. Interdire le remplacement des fichiers existants par la redirection. Quitter aprs avoir lu et excut une commande. Ne pas suivre les liens symboliques dans les commandes qui changent le rpertoire de travail. Utiliser le rpertoire physique. Indique si le shell a t dmarr en mode restreint. Cette valeur est en lecture seule. SHELLOPTS LR La liste des options du shell actives. La commande interne source utilise la valeur de $PATH pour trouver le rpertoire qui contient le fichier fourni en argument. Type var. denv.

522

[05/03/08]

Option de set

Nom complet de set

Option de shopt

force_fignore

hostcomplete

no_empty_ cmd_completion

progcomp

-C

noclobber

-t

onecmd

-P

physical

restricted_shell

Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

sourcepath

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description 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. 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. 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. T 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]}. Un tableau contenant les noms des fichiers sources qui correspondent aux lments de la variable tableau $FUNCNAME. Toute capture de ERR est hrite par les fonctions shell, les substitutions de commandes et les commandes excutes dans un sous-shell. BASH_ARGC T Type var. denv.

[05/03/08]

Option de set

Nom complet de set

Option de shopt

BASH_ARGV

BASH_COMMAND

Ajuster le comportement du shell avec set, shopt et les variables

BASH_LINENO

BASH_SOURCE

-E

errtrace

523

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description 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. 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. Toute capture de DEBUG est hrite par les fonctions shell, les substitutions de commandes et les commandes excutes dans un sous-shell. LINENO U Le numro de la ligne qui vient dtre excute dans un script ou une fonction. Lire des commandes et vrifier la syntaxe, mais ne pas les excuter. Elle est ignore dans les shells interactifs. Afficher les lignes dentre du shell avant de les excuter. Afficher les commandes, aprs les expansion, avant de les excuter. Type var. denv.

524

[05/03/08]

Option de set

Nom complet de set

Option de shopt

extdebug

-T

functrace

-n

noexec

-v

verbose

Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

-x

xtrace

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement 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. 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. Exporter toutes les variables dfinies ou modifies par la suite. BASH_ENV BASH_EXECUTION_ STRING BASH_VERSINFO RT Le nom dun fichier dfinissant lenvironnement excuter lors de linvocation du shell. Largument de loption dinvocation -c. Les informations de version de cette instance de bash. Chaque lment du tableau dtient une partie du numro de version. Le numro de version de cette instance de bash. R Les options passes lors de linvocation du shell. 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 messages derreurs du shell sont affichs en respectant le format standard de GNU. BASH_SUBSHELL Type var. denv.

[05/03/08]

Option de set

Nom complet de set

Option de shopt

SHLVL

-a

allexport

Ajuster le comportement du shell avec set, shopt et les variables

BASH_VERSION -

gnu_errfmt HOME

525

Elodie FRITSCH <elodie.fritsch@total.com>

Le rpertoire personnel (daccueil).

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description Le nom de lhte courant. Le type de machine sur laquelle sexcute bash. bash envoie SIGHUP toutes les tches lors de la terminaison dun shell douverture de session interactif. Sans autre argument, dsaffecter les paramtres positionnels. Sinon, les paramtres positionnels prennent la valeur des arguments suivants (mme sils commencent par -). IFS 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. Placer les arguments de keyword dans lenvironnement dune commande. LANG 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. HOSTNAME HOSTTYPE Type var. denv.

526

[05/03/08]

Option de set

Nom complet de set

Option de shopt

huponexit

--

-k

keyword

LC_ALL LC_COLLATE LC_CTYPE

Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description Dtermine les paramtres rgionaux servant la traduction des chanes entre guillemets prcdes dun symbole $. Dtermine les paramtres rgionaux servant la mise en forme des nombres. Indique que bash a t dmarr comme un shell douverture de session. Cette valeur est en lecture seule. MACHTYPE PATH SECONDS U L Une chane qui dcrit le systme sur lequel bash sexcute. Le chemin de recherche des commandes. Le nombre de secondes coules depuis linvocation du shell. Le shell effectue lexpansion des crochets. Elle est active par dfaut. Les noms de fichiers qui commencent par un . sont pris en compte lors de lexpansion du nom de chemin. Les alias sont dvelopps. 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. GLOBIGNORE L La liste des motifs dfinissant les noms de fichiers ignorer lors de lexpansion des noms de chemins. LC_MESSAGES Type var. denv.

[05/03/08]

Option de set

Nom complet de set

Option de shopt

LC_NUMERIC

login_shell

-B

braceexpand

dotglob

Ajuster le comportement du shell avec set, shopt et les variables

expand_aliases

extglob

failglob

527

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description La compilation des noms de chemins se fait de manire insensible la casse. Dsactiver lexpansion du nom de chemin. Les motifs qui ne correspondent aucun fichier sont remplacs par des chanes nulles et non par eux-mmes. 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. Activer le hachage des commandes. Tenter denregistrer toutes les lignes dune commande sur plusieurs lignes dans une mme entre de lhistorique. Lhistorique est ajout au fichier indiqu par la valeur de la variable $HISTFILE lorsque le shell se termine, au lieu dcraser le fichier. histchars HISTCMD HISTCONTROL U Prcise les caractres de contrle de lhistorique. Par dfaut, il sagit de la chane !^#. 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). Type var. denv.

528

[05/03/08]

Option de set

Nom complet de set

Option de shopt

nocaseglob

-f

noglob

nullglob

checkhash

-h

hashall

cmdhist

histappend

Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description Activer la substitution dhistorique avec !. Elle est active par dfaut dans les shells interactifs. HISTFILE HISTFILESIZE HISTIGNORE Le nom du fichier dhistorique des commandes. Le nombre maximum de lignes conserves dans le fichier dhistorique. Une liste de motifs qui dterminent ce qui entre dans lhistorique. Activer lhistorique des commandes. Elle est active par dfaut dans les shells interactifs. Si readline est utilise, il est possible de remodifier une substitution dhistorique qui a chou. HISTSIZE HISTTIMEFORMAT Le nombre de lignes conserves dans lhistorique des commandes. 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. 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. Type var. denv.

[05/03/08]

Option de set

Nom complet de set

Option de shopt

-H

histexpand

history

Ajuster le comportement du shell avec set, shopt et les variables

histreedit

histverify

529

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description 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. IGNOREEOF Le nombre de caractres EOF reus avant de clore un shell interactif. Interdire la sortie du shell par Ctrl-D. Lorsquun argument de cd nest pas un rpertoire, il est considr comme un nom de variable qui contient le rpertoire cible. CDPATH L Une liste des rpertoires recherchs par la commande cd. 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. Vrifier la taille de la fentre aprs chaque commande et, si elle a chang, actualiser les variables $LINES et $COLUMNS en consquence. DIRSTACK FCEDIT RTU Le contenu actuel de la pile de rpertoires. Utiliser ldition de la ligne de commande de type Emacs. Lditeur par dfaut de la commande fc. Accepter les mots commenant par #, en ignorant tous les caractres suivants de la ligne, dans un shell interactif. Type var. denv.

530

[05/03/08]

Option de set

Nom complet de set

Option de shopt

lithist

ignoreeof

cdable_vars

cdspell

checkwinsize

emacs

Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

interactive_ comments

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description Le rpertoire de travail prcdent. 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. PS1 PS2 PS3 PS4 PWD La chane de linvite principale. La chane de linvite pour les continuations de ligne. La chane de linvite de la commande select. La chane de linvite de loption xtrace. Le rpertoire de travail. La commande interne shift affiche une erreur lorsque le dcalage dpasse le dernier paramtre positionnel. TIMEFORMAT TMOUT Prcise le format de sortie du mot rserv time dans un tube de commandes. Fixe un entier positif, elle indique le nombre de secondes aprs lequel le shell se termine automatiquement en labsence de saisie. R Le dernier argument de la commande prcdente. Utiliser ldition de la ligne de commande de type vi. auto_resume Dtermine le fonctionnement du contrle des tches (les valeurs sont exact, substring ou autre chose que ces mots-cls). Activer le contrle des tches. Elle est active par dfaut dans les shells interactifs. OLDPWD PROMPT_COMMAND Type var. denv.

[05/03/08]

Option de set

Nom complet de set

Option de shopt

promptvars

Ajuster le comportement du shell avec set, shopt et les variables

shift_verbose

vi

Elodie FRITSCH <elodie.fritsch@total.com>

-m

monitor

531

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description Afficher immdiatement le code de sortie des tches darrire-plan qui se terminent. MAIL MAILCHECK MAILPATH L Le nom du fichier consulter pour dterminer larrive dun nouveau message lectronique. Lintervalle (en secondes) de vrification de larrive dun nouveau message lectronique. La liste des noms de fichiers consulter pour dterminer larrive dun nouveau message lectronique, si $MAIL nest pas dfinie. 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 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. PIPESTATUS T Une variable tableau contenant la liste des codes de sortie des processus impliqus dans le dernier tube excut au premier plan. Changer le comportement afin quil se conforme la norme POSIX 1003.2 l o ce nest pas le cas par dfaut. Type var. denv.

532

[05/03/08]

Option de set

Nom complet de set

Option de shopt

-b

notify

mailwarn

pipefail

Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

posix

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description 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. echo dveloppe par dfaut les squences dchappement base de barre oblique inverse. 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. Le nom du shell ou du script. 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). R 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. POSIXLY_CORRECT Type var. denv.

[05/03/08]

Option de set

Nom complet de set

Option de shopt

xpg_echo

0 * R

Ajuster le comportement du shell avec set, shopt et les variables

BASH

533

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description Lidentifiant du processus du shell. 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 !. EUID ! R R Lidentifiant dutilisateur rel de lutilisateur connect. 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. GROUPS RT Un tableau contenant la liste des groupes dont lutilisateur courant est membre. Considrer les variables non dfinies comme des erreurs et non comme nulles. OPTARG OPTERR OPTIND OSTYPE # PPID R R La valeur du dernier argument doption trait par getopts. Si elle vaut 1, les messages derreur de getopts sont affichs. Le numro du premier argument aprs les options. Le systme dexploitation sur lequel bash sexcute. Le nombre darguments passs au script ou la fonction. Lidentifiant du processus parent. $ R Type var. denv.

534

[05/03/08]

Option de set

Nom complet de set

Option de shopt

-e

errexit

execfail

-u

nounset

Annexe A Listes de rfrence

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau A-8. Ajuster le comportement du shell avec set, shopt et les variables (suite)
Variable denvironnement Description Le script sexcute en mode privilgi (suid). ? RANDOM REPLY U R Le code de sortie de la commande prcdente. 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. Le nom de chemin complet du shell. R Lidentifiant de lutilisateur courant. Type var. denv.

[05/03/08]

Option de set

Nom complet de set

Option de shopt

-p

privileged

SHELL UID

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 -a fichier -b fichier -c fichier -d fichier -e fichier -f fichier -g fichier -G fichier -h fichier -k fichier -L fichier -n chane -N fichier -O fichier -p fichier -r fichier -s fichier -S fichier -t N -u fichier -w fichier -x fichier -z chane fichierA -nt fichierB fichierA -ot fichierB fichierA -ef fichierB chaneA = chaneB chaneA == chaneB Vrai si fichier existe, obsolte, identique -e. fichier existe et est un priphrique en mode bloc. fichier existe et est un priphrique en mode caractre. fichier existe et est un rpertoire. fichier existe, identique -a. fichier existe et est un fichier normal. fichier existe et son bit SGID (set group ID) est positionn. fichier existe et appartient lidentifiant de groupe rel. fichier existe et est un lien symbolique, identique -L. fichier existe et son bit sticky est positionn. fichier existe et est un lien symbolique, identique -h. chane nest pas nulle. fichier a t modifi depuis sa dernire lecture. fichier existe et appartient lidentifiant dutilisateur rel. fichier existe et est un tube nomm ou non (fichier FIFO). fichier existe et peut tre lu. fichier existe et nest pas vide. fichier existe et est une socket. Le descripteur de fichier N pointe vers un terminal. fichier existe et son bit SUID (set user ID) est positionn. fichier existe et peut tre modifi. fichier existe et peut tre excut, ou fichier est un rpertoire que lon peut parcourir. chane a une longueur gale zro. La date de modification de fichierA est plus rcente que celle de fichierB. La date de modification de fichierA est plus ancienne que celle de fichierB. fichierA et fichierB dsigne le mme fichier. chaneA est gale chaneB (version POSIX). chaneA est gale chaneB.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Redirection des entres/sorties


Tableau A-9. Oprateurs de test (suite)
Oprateur chaneA != chaneB chaneA =~ expreg chaneA < chaneB chaneA > chaneB exprA -eq exprB exprA -ne exprB exprA -lt exprB exprA -gt exprB exprA -le exprB exprA -ge exprB exprA -a exprB exprA -o exprB
a.

537

Vrai si chaneA ne correspond pas chaneB. chaneA correspond lexpression rgulire tendue regexpa. chaneA se trouve avant chaneB dans lordre lexicographique. chaneA se trouve aprs chaneB dans lordre lexicographique. Les expressions arithmtiques exprA et exprB sont gales. Les expressions arithmtiques exprA et exprB sont diffrentes. exprA est infrieure exprB. exprA est suprieure exprB. exprA est infrieure ou gale exprB. exprA est suprieure ou gale exprB. exprA est vraie et exprB est vraie. exprA est vraie ou exprB est vraie.

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 cmd1 | cmd2 > fichier < fichier >> fichier >| fichier n>| fichier <> fichier Fonction Tube ; la sortie standard de cmd1 devient lentre standard de cmd2. La sortie standard est redirige vers fichier. Lentre standard est lue depuis fichier. La sortie standard est redirige vers fichier ; si fichier existe dj, elle lui est ajoute. La sortie standard est redirige vers fichier mme si noclobber est positionne. La sortie standard du descripteur de fichier n est redirige vers fichier mme si noclobber est positionne. fichier est utilis comme entre et sortie standard.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

538
Tableau A-10. Redirection des entres/sorties (suite)
Redirecteur n<> fichier << tiquette n> fichier n< fichier >> fichier n>& n<& n>&m n<&m &>fichier <&>&n>&n<&n>&mot Fonction

Annexe A Listes de rfrence

fichier est utilis comme entre et sortie standard pour le descripteur de fichier n. Here document. Le descripteur de fichier n est redirig vers fichier. Le descripteur de fichier n est pris depuis fichier. Le descripteur de fichier n est redirig vers fichier ; si fichier existe dj, il lui est ajout. La sortie standard est duplique vers le descripteur de fichier n. Lentre standard est duplique depuis le descripteur de fichier n. Le descripteur de fichier n devient une copie du descripteur de fichier de sortie m. Le descripteur de fichier n devient une copie du descripteur de fichier dentre m. La sortie et lerreur standard sont rediriges vers fichier. Lentre standard est ferme. La sortie standard est ferme. La sortie du descripteur de fichier n est ferme. Lentre du descripteur de fichier n est ferme. 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. 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. Le descripteur de fichier chiffre devient le descripteur de fichier n, ou bien la sortie standard (descripteur de fichier 1) si n est omis. 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.

n<&mot

n>&chiffren<&chiffre-

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 -e -E -n Fonction Activer linterprtation des caractres chapps laide de la barre oblique inverse. Dsactiver linterprtation des caractres chapps laide de la barre oblique inverse sur les systmes qui configurent ce mode par dfaut. 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 \a \b \c \e \E \f \n \r \t \v \nnnn \0nnn \xHH \\ Caractre affich Alarme ou Ctrl-G (sonnerie). Espace arrire ou Ctrl-H. Supprimer le saut de ligne final. Caractre dchappement (identique \E). Caractre dchappement. Changement de page ou Ctrl-L. Saut de ligne (non la fin dune commande) ou Ctrl-J. Retour (Entre) ou Ctrl-M. Tabulation ou Ctrl-I. Tabulation verticale ou Ctrl-K. Le caractre sur 8 bits dont la valeur octale (base 8) est donne par nnn (sur 1 3 chiffres). Le caractre sur 8 bits dont la valeur octale (base 8) est donne par nnn (sur 0 3 chiffres). 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 %c %d, %i %e %E %f %g %G %o %s %u %x %X %% Signification Caractre ASCII (affiche le premier caractre de largument correspondant). Entier dcimal (base 10). Format en virgule flottante ([-]d.prcisione[+-]dd) voir les explications de prcision aprs ce tableau. Format en virgule flottante ([-]d.prcisionE[+-]dd). Format en virgule flottante ([-]ddd.prcision). Conversion %e ou %f, selon celle qui est la plus courte, avec suppression des zros de fin. Conversion %E ou %f, selon celle qui est la plus courte, avec suppression des zros de fin. Valeur octale non signe. Chane de caractres. Valeur dcimale non signe. Nombre hexadcimal non sign ; utilise a-f pour les valeurs 10 15. 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 %d, %I, %o, %u, %x, %X Signification de prcision 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. 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. Le nombre de chiffres droite de la virgule. Le nombre maximum de chiffres significatifs. Le nombre maximum de caractres affichs.

%e, %E

%f %g, %G %s

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

542

Annexe A Listes de rfrence

Tableau A-14. Signification de prcision selon lindicateur de format de printf (suite)


Format %b Signification de prcision (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). (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.

%q

%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 \e \a \b \f \n \r \t \v \' \" \\ Signification Caractre dchappement. Caractre dalarme. Caractre despace arrire. Caractre de changement de page. Caractre de saut de ligne. Caractre de retour chariot. Caractre de tabulation. Caractre de tabulation verticale. Caractre de lapostrophe. Caractre des guillemets. Caractre de la barre oblique inverse.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

printf
Tableau A-15. Squences dchappement de printf (suite)
Squence dchappement \nnn \xHH Signification

543

Le caractre sur 8 bits dont la valeur ASCII est donne par le chiffre octal nnn (sur 1 3 chiffres). 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 espace + # Description Aligner gauche dans le champ la valeur mise en forme. 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 printf '%f\n' $PI # Non voulu printf '%f.5\n' $PI Rsultat 3.141593 3.14.5 Commentaires Notez larrondi par dfaut. 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

544
Tableau A-17. Exemples de printf (suite)
Instruction printf printf '%.5f\n' $PI printf '%+.2f\n' $PI printf '[%.4s]\n' s chaine Rsultat 3.14159 +3.14 [s] [chai] [ s] [chaine]

Annexe A Listes de rfrence

Commentaires Accorde cinq chiffres droite de la virgule. Signe + de dbut, uniquement deux chiffres aprs la virgule. Tronque quatre caractres. Avec un seul caractre, la sortie ne contient que lui. La chane de format est rutilise. Garantit un champ dau moins quatre caractres, aligns droite. Le contenu nest pas tronqu. 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.

printf '[%4s]\n' s chaine

printf '[%-4.4s]\n' s chaine [s ] [chai]

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 tabulation puis 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 %% %a %A Description Un symbole % littral. Le nom abrg du jour de la semaine conformment aux paramtres rgionaux (lun..dim). Le nom complet du jour de la semaine conformment aux paramtres rgionaux (lundi..dimanche).

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Mettre en forme la date et lheure avec strftime


Tableau A-18. Code de format de strftime (suite)
Format %B %b ou %h %c %C %d %D Description

545

Le nom complet du mois conformment aux paramtres rgionaux (janvier..dcembre). Le nom abrg du mois conformment aux paramtres rgionaux (jan..dc). La reprsentation par dfaut/prfre de la date et de lheure conformment aux paramtres rgionaux. Le sicle (une anne divise par 100 et convertie en un entier) sous forme de nombre dcimal (00..99). Le jour du mois sous forme de nombre dcimal (01..31). 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. Le jour du mois sous forme dun nombre dcimal complt par une espace ( 1..31). 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. Lanne sur deux chiffres correspondant au numro de la semaine %V (AA). Lanne sur quatre chiffres correspondant au numro de la semaine %V (CCAA). Lheure (sur 24 heures) sous forme de nombre dcimal (00..23). Le nom abrg du mois conformment aux paramtres rgionaux (jan..dc). Lheure (sur 12 heures) sous forme de nombre dcimal (01..12). Le jour de lanne sous forme de nombre dcimal (001..366). Lheure (sur 24 heures) sous forme de nombre dcimal complt par une espace ( 0..23). Lheure (sur 12 heures) sous forme de nombre dcimal complt par une espace ( 1..12). Le mois sous forme de nombre dcimal (01..12). Les minutes sous forme de nombre dcimal (00..59). Un saut de ligne littral. Les nanosecondes (000000000..999999999). [GNU] Lindicateur rgional de AM ou PM . Lindicateur rgional de am ou pm . [GNU] Lheure (sur 12 heures) avec la notation AM/PM (HH:MM:SS AM/PM) conformment aux paramtres rgionaux. Lheure au format %H:%M (HH:MM).

%e %F %g %G %H %h ou %b %I %j %k %l %m %M %n %N %p %P %r %R

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

546
Tableau A-18. Code de format de strftime (suite)
Format %s %S %t %T %u %U %v %V Description

Annexe A Listes de rfrence

Le nombre de secondes coules depuis lorigine (le 1er janvier 1970 00:00:00 UTC). Les secondes sous forme de nombre dcimal (00..61). Lintervalle est (0061) et non (00-59) afin dautoriser les secondes intercalaires. Une tabulation littrale. Lheure au format %H:%M:%S (HH:MM:SS). Le jour de la semaine (le lundi tant le premier jour) sous forme de nombre dcimal (1..7). Le numro de la semaine dans lanne (le dimanche tant le premier jour de la semaine) sous forme de nombre dcimal (00..53). La date au format %e-%b-%Y (D-MMM-CCAA). [Non standard] 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. Le jour de la semaine (le dimanche tant le premier jour) sous forme de nombre dcimal (0..6). Le numro de la semaine de lanne (le lundi tant le premier jour de la semaine) sous forme de nombre dcimal (00..53). La reprsentation de la date conformment aux paramtres rgionaux. La reprsentation de lheure conformment aux paramtres rgionaux. Lanne sans le sicle sous forme de nombre dcimal (00..99). Lanne avec le sicle sous forme de nombre dcimal. Le fuseau horaire, comme un dcalage par rapport lUTC au format ISO 8601 [-]hhmm. Le nom du fuseau horaire.

%w %W %x %X %y %Y %z %Z

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Oprateurs pour la correspondance de motifs tendue extglob


Tableau A-19. Caractres pour la correspondance de motifs (suite)
Caractre [ ... ] [! ... ] ou [^ ... ] Signification

547

Correspondance avec lun des caractres placs entre les crochets. 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

548

Annexe A Listes de rfrence

Squences dchappement de tr
Tableau A-21. Squences dchappement de tr
Squence \ooo \\ \a \b \f \n \r \t \v Signification 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). Une sonnerie audio , le caractre ASCII BEL (puisque b est pris pour lespace arrire). Lespace arrire. Le changement de page. Le saut de ligne. Le retour chariot. La tabulation (parfois appele tabulation horizontale). 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Syntaxe du fichier dinitiation de readline


Tableau A-22. Paramtres de configuration de Readline
Variable bell-style Description

549

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. 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. La chane insrer au dbut de la ligne lorsque la commande insert-comment est excute. Par dfaut, il sagit dun caractre #. 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. 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. 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. 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. 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. 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. Si elle vaut on, le dveloppement du tilde (~) est effectu lorsque Readline tente la compltion de mot. La valeur par dfaut est off.

bind-tty-special-chars

comment-begin

completion-ignore-case

completion-query-items

convert-meta

disable-completion

editing-mode

enable-keypad

expand-tilde

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

550

Annexe A Listes de rfrence

Tableau A-22. Paramtres de configuration de Readline (suite)


Variable history-preserve-point Description 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. 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. 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. 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. 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. Si elle vaut on, une barre oblique est ajoute aux noms de rpertoires complts. La valeur par dfaut est on. Pour la valeur on, Readline affiche une astrisque (*) au dbut des lignes de lhistorique qui ont t modifies. La valeur par dfaut est off. 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. 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. 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.

horizontal-scroll-mode

input-meta

isearch-terminators

keymap

mark-directories mark-modified-lines

mark-symlinkeddirectories

match-hidden-files

output-meta

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Commande du mode Emacs


Tableau A-22. Paramtres de configuration de Readline (suite)
Variable page-completions Description

551

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. Lorsque cette variable vaut on, Readline affiche les compltions tries horizontalement par ordre alphabtique et non plus verticalement. La valeur par dfaut est off. 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. 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. 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.

print-completionshorizontally show-all-if-ambiguous

show-all-if-unmodified

visible-stats

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 Ctrl-A Ctrl-B Ctrl-D Ctrl-E Ctrl-F Ctrl-G Ctrl-J Ctrl-K Ctrl-L Signification Dplacement en dbut de ligne. Dplacement dun caractre vers larrire. Suppression dun caractre vers lavant. Dplacement en fin de ligne. Dplacement dun caractre vers lavant. Annule la commande ddition en cours et met un bip. Identique Entre. Suppresion vers lavant jusqu la fin de la ligne. Effacement de lcran, puis raffichage de la ligne.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

552
Tableau A-23. Commandes du mode Emacs (suite)
Commande Ctrl-M Ctrl-N Ctrl-O Ctrl-P Ctrl-R Ctrl-S Ctrl-T Ctrl-U Ctrl-V Ctrl-V Tab Ctrl-W Ctrl-X / Ctrl-X ~ Ctrl-X $ Ctrl-X @ Ctrl-X ! Ctrl-X ( Ctrl-X ) Ctrl-X e Ctrl-X Ctrl-R Ctrl-X Ctrl-V Ctrl-Y Suppr Ctrl-[ chap-B chap-C chap-D chap-F chap-L chap-N chap-P chap-R chap-T chap-U chap-Ctrl-E chap-Ctrl-H Signification Identique Entre.

Annexe A Listes de rfrence

Ligne suivant de lhistorique des commandes. Identique Entre, puis affichage de la ligne suivante de lhistorique. Ligne prcdente de lhistorique des commandes. Recherche vers larrire. Recherche vers lavant. Interversion de deux caractres. Suppresion de la ligne vers larrire partir du dbut jusquau point. Entre tel quel du prochain caractre suivant. Insertion dune tabulation. Suppresion du mot avant le curseur, lespace servant de dlimiteur. Liste des compltions de noms de fichiers pour le mot courant. Liste des compltions de noms dutilisateurs pour le mot courant. Liste des compltions de variables shell pour le mot courant. Liste des compltions de noms dhtes pour le mot courant. Liste des compltions de noms de commandes pour le mot courant. Dbut de lenregistrement des caractres dans la macro clavier en cours. Fin de lenregistrement des caractres dans la macro clavier en cours. Nouvelle excution de la dernire macro clavier dfinie. Lecture du contenu du fichier dinitialisation de readline. Affichage des informations de version de cette instance de bash. Rcupration (yank) du dernier lment dtruit. Effacement vers larrire dun caractre. Identique chap (la plupart des claviers). Dplacement dun mot vers larrire. Conversion du mot aprs le point en lettres capitales. Suppression dun mot vers lavant. Dplacement dun mot vers lavant. Conversion du mot aprs le point en lettres minuscules. Recherche vers lavant non progressive. Recherche vers larrire non progressive. Annulation de toutes les modifications apportes cette ligne. Interversion de deux mots. Conversion du mot aprs le point en lettres majuscules. Expansion des alias, de lhistorique et des mots sur la ligne. Suppression dun mot vers larrire.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Commandes du mode vi
Tableau A-23. Commandes du mode Emacs (suite)
Commande chap-Ctrl-Y chap-Suppr chap-^ chap-< chap-> chap-. chap-_ Tab chap-? chap-/ chap-~ chap-$ chap-@ chap-! chap-Tab chap-~ chap-\ chap-* chap-= chap-{ Signification

553

Insertion du premier argument de la commande prcdente (gnralement le deuxime mot) au point courant. Suppression dun mot vers larrire. Expansion de lhistorique sur la ligne. Dplacement sur la premire ligne du fichier dhistorique. Dplacement sur la dernire ligne du fichier dhistorique. Insertion du dernier mot de la commande de la ligne prcdente aprs le point. Identique la prcdente. Compltion de noms de fichiers sur le mot courant. Liste des compltions possibles pour le texte avant le point. Tentative de compltion de noms de fichiers sur le mot courant. Tentative de compltion de noms dutilisateurs sur le mot courant. Tentative de compltion de variables sur le mot courant. Tentative de compltion de noms dhtes sur le mot courant. Tentative de compltion de noms de commandes sur le mot courant. Tentative de compltion partir de lhistorique des commandes. Tentative de dveloppement du tilde sur le mot courant. Suppression de toutes les espaces et des tabulations autour du point. Insertion avant le point de toutes les compltions qui seraient gnres par chap-=. Liste des compltions possibles avant le point. 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 h l w b W 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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

554
Tableau A-24. Commandes du mode vi (suite)
Commande B e E 0 . ^ $ i a I A R dh dl db dw dB dW d$ d0 D dd C cc x X k ou j ou + G /chane ?chane n N fx Fx Signification

Annexe A Listes de rfrence

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. Suppression dun caractre vers larrire. Suppression dun caractre vers lavant. Suppression dun mot vers larrire. Suppression dun mot vers lavant. Suppression dun mot non blanc vers larrire. Suppression dun mot non blanc vers lavant. Suppression jusqu la fin de la ligne. Suppression jusquau dbut de la ligne. quivalent d$ (suppression jusqu la fin de la ligne). quivalent 0d$ (suppression de la ligne entire). quivalent c$ (suppression jusqu la fin de la ligne, passage en mode saisie). 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). Dplacement dune ligne vers larrire. Dplacement dune ligne vers lavant. Dplacement vers la ligne indique par le compteur de rptition. Recherche de chane vers lavant. Recherche de chane vers larrire. Rptition de la recherche vers lavant. Rptition de la recherche larrire. Dplacement vers la droite sur loccurrence suivante de x. Dplacement vers la gauche sur loccurrence prcdente de x.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau des valeurs ASCII


Tableau A-24. Commandes du mode vi (suite)
Commande tx Tx ; , \ * \= ~ \ Ctrl-L # Signification

555

Dplacement vers la droite sur loccurrence suivante de x, puis dplacement dune espace vers larrire. 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. 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 0 1 2 3 4 5 6 7 8 9 10 11 12 13 Octal 000 001 002 003 004 005 006 007 010 011 012 013 014 015 Hexa. 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d ASCII ^@ ^A ^B ^C ^D ^E ^F ^G ^H ^I ^J ^K ^L ^M Entier 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Octal 016 017 020 021 022 023 024 025 026 027 030 031 032 033 Hexa. 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b ASCII ^N ^O ^P ^Q ^R ^S ^T ^U ^V ^W ^X ^Y ^Z ^[

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

556
Entier 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 Octal 034 035 036 037 040 041 042 043 044 045 046 047 050 051 052 053 054 055 056 057 060 061 062 063 064 065 066 067 070 071 072 073 074 075 076 077 100 101 Hexa. 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 ! # $ % & ( ) * + , . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A ASCII ^\ ^] ^^ ^_ Entier 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

Annexe A Listes de rfrence


Octal 102 103 104 105 106 107 110 111 112 113 114 115 116 117 120 121 122 123 124 125 126 127 130 131 132 133 134 135 136 137 140 141 142 143 144 145 146 147 Hexa. 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 ASCII B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Tableau des valeurs ASCII


Entier 104 105 106 107 108 109 110 111 112 113 114 115 Octal 150 151 152 153 154 155 156 157 160 161 162 163 Hexa. 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 ASCII h i j k l m n o p q r s Entier 116 117 118 119 120 121 122 123 124 125 126 127 Octal 164 165 166 167 170 171 172 173 174 175 176 177 Hexa. 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f

557
ASCII t u v w x y z { | } ~ ^?

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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
./bashdb

Description
Exemple dimplmentation obsolte dun dbogueur bash. Code de compltion du shell. Exemples de fonctions. Fonctions pour les array_sort, reverse). tableaux (ashift,

Voir aussi

./complete ./functions ./functions/array-stuff ./functions/array-to-string ./functions/autoload ./functions/autoload.v2 ./functions/autoload.v3 ./functions/basename ./functions/basename2 ./functions/coproc.bash ./functions/coshell.bash ./functions/coshell.README ./functions/csh-compat ./functions/dirfuncs ./functions/dirname ./functions/emptydir ./functions/exitstat ./functions/external

Convertir un tableau en une chane. Une version presque compatible avec ksh de ksh autoload (sans le chargement paresseux). Une version presque compatible avec ksh de ksh autoload (sans le chargement paresseux). Une version plus compatible avec ksh de ksh autoload (avec le chargement paresseux). Remplaant pour basename(1). basename Fonctions basename(1) et dirname(1) rapides basename, pour bash/sh. dirname Dmarrer, grer et terminer des co-processus. Grer les co-processus coprocess.bash). du shell (voir

README pour coshell et coproc. Paquetage de compatibilit avec le shell C. Fonctions de manipulation des rpertoires tires du livre The Korn Shell. Remplaant pour dirname(1). Dterminer si un rpertoire est vide. Afficher le code de sortie des processus. Comme command, mais force lutilisation dune commande externe. dirname csh

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Fichiers de dmarrage
Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin
./functions/fact ./functions/fstty ./functions/func ./functions/gethtml ./functions/getoptx.bash ./functions/inetaddr ./functions/inpath ./functions/isnum.bash ./functions/isnum2 ./functions/isvalidip ./functions/jdate.bash ./functions/jj.bash ./functions/keep ./functions/ksh-cd ./functions/ksh-compat-test ./functions/kshenv ./functions/login ./functions/lowercase ./functions/manpage ./functions/mhfold

561

Description
Fonction rcursive de calcul dune factorielle.

Voir aussi

Interface pour synchroniser les modifications de stty.bash TERM avec stty(1) et bind de readline. Afficher les dfinitions des fonctions nommes en argument. Obtenir une page web depuis un serveur distant (wget(1) dans bash). Fonction getopt qui analyse les options donnes sous forme de noms longs. Conversion dune adresse internet (inet2hex et hex2inet). Retourner zro si largument se trouve dans le inpath chemin et sil est excutable. Vrifier si la saisie de lutilisateur est une valeur numrique ou un caractre. Vrifier si la saisie de lutilisateur est une valeur numrique, en virgule f lottante. Vrifier si la saisie de lutilisateur est une adresse IP valide. Conversion de date ordinale. Rechercher des tches en cours dexcution. Tenter de garder certains programmes au premier plan et en excution. Commande cd de type ksh : cd [change]]. Test arithmtique de type ksh. [-LP] [rp ksh ksh

Fonctions et alias pour obtenir le dbut dun ksh environnement ksh sous bash. Remplacer les commandes internes login et newgrp des anciens shells Bourne. Renommer les fichiers en minuscules. Trouver et afficher une page de manuel. Afficher les dossiers MH, utile uniquement parce que folders(1) naffiche pas les dates et heures de modification. Indiquer les changements dtat des tches. Fonctions de gestion du chemin (no_path, path add_path, pre-path, del_path). README. Parcourir rcursivement un rpertoire. Clone de la commande repeat interne au shell C. repeat, csh Clone de la commande repeat interne au shell C. repeat, csh rename lower fman

./functions/notify.bash ./functions/pathfuncs ./functions/README ./functions/recurse ./functions/repeat2 ./functions/repeat3

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

562

Annexe B Exemples fournis avec bash

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin
./functions/seq ./functions/seq2 ./functions/shcat ./functions/shcat2 ./functions/sort-pos-params ./functions/substr ./functions/substr2 ./functions/term ./functions/whatis ./functions/whence ./functions/which ./functions/xalias.bash ./functions/xfind.bash ./loadables/ ./loadables/basename.c ./loadables/cat.c ./loadables/cut.c ./loadables/dirname.c ./loadables/finfo.c ./loadables/getconf.c ./loadables/getconf.h ./loadables/head.c ./loadables/hello.c ./loadables/id.c ./loadables/ln.c ./loadables/logname.c

Description
Gnrer une suite de m n ; m vaut par dfaut 1. Gnrer une suite de m n ; m vaut par dfaut 1. Affichage pagin bas sur Readline. Affichage pagin bas sur Readline. Trier les paramtres positionnels.

Voir aussi

cat, readline pager cat, readline pager

Fonction dmulation de lancienne commande ksh interne de ksh. Fonction dmulation de lancienne commande ksh interne de ksh. Fonction qui fixe le type de terminal de manire interactive ou non. Implmentation de la commande whatis(1) interne sh pour Unix 10e dition. Version presque compatible avec ksh de la commande whence(1). muler la commande which(1) telle quelle existe dans FreeBSD. Convertir des commandes et alias csh en fonc- csh, aliasconv tions bash. Clone de find(1). Exemples de remplaants chargeables. Retourner le nom de chemin sans la partie basename rpertoire. Remplaant de cat(1) sans option la version cat, readline normale de cat. pager Remplaant de cut(1). Retourner la partie rpertoire du nom de che- dirname min. Afficher des informations sur le fichier. Utilitaire getconf POSIX.2 Dfinitions de remplacement pour celles non fournies par le systme. Copier la premire partie des fichiers. Exemple Hello World indispensable. Identit POSIX.2 de lutilisateur. Crer des liens. Afficher le nom de connexion de lutilisateur courant.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Fichiers de dmarrage
Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin
./loadables/Makefile.in ./loadables/mkdir.c ./loadables/necho.c ./loadables/pathchk.c ./loadables/print.c ./loadables/printenv.c ./loadables/push.c ./loadables/README ./loadables/realpath.c ./loadables/rmdir.c ./loadables/sleep.c ./loadables/strftime.c ./loadables/sync.c ./loadables/tee.c ./loadables/template.c ./loadables/truefalse.c ./loadables/tty.c ./loadables/uname.c ./loadables/unlink.c ./loadables/whoami.c ./loadables/perl/

563

Description
Fichier makefile simple pour les exemples de commandes internes chargeables. Crer des rpertoires. echo sans options ni interprtation des arguments. Vrifier la validit et la portabilit des noms de chemins. Commande interne print chargeable de type ksh93. Clone minimal de la commande printenv(1) de BSD. Qui se souvient de TOPS-20 ? README. Obtenir des noms de chemins canoniques, en rsolvant les liens symboliques. Supprimer un rpertoire. Attendre pendant des fractions de seconde. Interface interne chargeable pour strftime(3). Synchroniser les disques en forant les critures en attente. Dupliquer lentre standard. Modle de commande interne chargeable. Commandes internes true et false. Retourner le nom du terminal. Afficher des informations sur le systme. Supprimer lentre dun rpertoire. Afficher le nom de lutilisateur courant. Comment implmenter un interprteur Perl en bash. Divers.

Voir aussi

./misc ./misc/aliasconv.bash ./misc/aliasconv.sh ./misc/cshtobash ./misc/README ./misc/suncmd.termcap

Convertir des alias csh en alias et fonctions bash. csh, xalias Convertir des alias csh en alias et fonctions bash. csh, xalias Convertir des alias, des variables denvironne- csh, xalias ment et des variables csh en quivalents bash. README. Chane TERMCAP de SunView.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

564

Annexe B Exemples fournis avec bash

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin
./obashdb

Description
Version modifie du dbogueur du shell Korn tire du livre Learning the Korn Shell de Bill Rosenblatt. Ensemble de scripts de Noah Friedman (mis jour avec la syntaxe de bash v2 par Chet Ramey). Exemples de pseudo-tableaux et dindices de sous-chanes. Fonctions employes par require.bash. Activer et dsactiver lentre sur 8 bits dans readline. Crer un fichier temporaire avec un nom unique. Convertir des nombres en anglais. Autorisations dutilisation des scripts de ce rpertoire. Une manire de fixer PS1 des chanes prdfinies. README.

Voir aussi

./scripts.noah ./scripts.noah/aref.bash ./scripts.noah/bash.sub.bash ./scripts.noah/meta.bash ./scripts.noah/mktmp.bash ./scripts.noah/number.bash ./scripts.noah/PERMISSION ./scripts.noah/prompt.bash ./scripts.noah/README ./scripts.noah/remap_keys.bash ./scripts.noah/require.bash ./scripts.noah/send_mail.bash ./scripts.noah/shcat.bash ./scripts.noah/source.bash ./scripts.noah/string.bash ./scripts.noah/stty.bash ./scripts.noah/y_or_n_p.bash

./scripts.noah/bash_version.bash Fonction de dcomposition de $BASH_VERSION.

Interface bind pour refaire des liaisons readline. readline Fonctions Lisp require / provide pour bash. Client SMTP crit en bash. Remplaant bash de cat(1). Remplaant de source qui utilise le rpertoire de travail. Les fonctions string(3) au niveau du shell. Interface stty(1) qui modifie galement les fstty liaisons de readline. Invite pour une rponse de type oui/non/quit- ask ter. Ensemble de scripts ksh de John DuBois (convertis la syntaxe de bash v2 par Chet Ramey). Convertir une archive arc en une archive tar compresse. Gnrateur de nombres alatoires avec des bor- random nes suprieures et infrieures, ainsi quune graine facultative. Convertir un numro de jour en un nom. cat

./scripts.v2 ./scripts.v2/arc2tarz ./scripts.v2/bashrand

./scripts.v2/cal2day.bash

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Fichiers de dmarrage
Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin
./scripts.v2/cdhist.bash ./scripts.v2/corename ./scripts.v2/fman ./scripts.v2/frcp ./scripts.v2/lowercase ./scripts.v2/ncp ./scripts.v2/newext ./scripts.v2/nmv ./scripts.v2/pages ./scripts.v2/PERMISSION ./scripts.v2/pf ./scripts.v2/pmtop ./scripts.v2/README ./scripts.v2/ren ./scripts.v2/rename ./scripts.v2/repeat ./scripts.v2/shprof ./scripts.v2/untar ./scripts.v2/uudec ./scripts.v2/uuenc ./scripts.v2/vtree ./scripts.v2/where

565

Description
Remplaant de cd acceptant une pile de rpertoires. Indiquer lorigine dun fichier core. Remplaant rapide de man(1). Copier des fichiers avec ftp(1), mais avec une syntaxe de type rcp. Passer des noms de fichiers en minuscules. Interface agrable pour cp(1) (avec -i, etc.). Modifier lextension dun ensemble de fichiers. Interface agrable pour mv(1) (avec -i, etc.). Afficher les pages indiques des fichiers. Autorisations dutilisation des scripts de ce rpertoire. Affichage pagin qui gre les fichiers compresss. top(1) pour SunOS 4.x et BSD/OS. README.

Voir aussi

manpage

rename lower rename rename

Renommer des fichiers en modifiant les parties rename qui correspondent un motif. Changer les noms des fichiers qui correspondent rename un motif. Excuter plusieurs fois une commande. Profileur de ligne pour les scripts bash. Extraire une archive tar (potentiellement compresse) dans un rpertoire. uudecode(1) prudent pour plusieurs fichiers. uuencode(1) pour plusieurs fichiers. Afficher une reprsentation graphique dune tree arborescence de rpertoires. Afficher lemplacement des commandes qui correspondent un motif. Exemples de scripts. Jeu daventure en bash ! mulateur de shell C. Affichage pagin bas sur Readline. Centrer un groupe de lignes. diteur de ligne qui utilise uniquement /bin/sh, /bin/dd et /bin/rm. csh cat, readline pager repeat

./scripts ./scripts/adventure.sh ./scripts/bcsh.sh ./scripts/cat.sh ./scripts/center ./scripts/dd-ex.sh

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

566

Annexe B Exemples fournis avec bash

Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin
./scripts/fixfiles.bash

Description
Parcourir rcursivement une arborescence et corriger les fichiers qui contiennent diffrents caractres invalides. Les invitables Tours de Hano en bash.

Voir aussi

./scripts/hanoi.bash ./scripts/inpath ./scripts/krand.bash ./scripts/line-input.bash

Rechercher dans $PATH un fichier de mme nom inpath que $1 ; retourner TRUE sil est trouv. Gnrer un nombre alatoire avec des bornes random entires. Routine de saisie de ligne pour le Bourne Again Shell de GNU avec les primitives de contrle du terminal. Version bash de la commande nohup. Tester la prcdence relative pour les oprateurs && et ||. Afficher une carte alatoire tire depuis un jeu random de cartes. README. Afficher du texte dfilant. Afficher du texte dfilant. Un script qui sauto-reproduit (prudence !). Convertir les autorisations symboliques de ls(1) en mode octal. Afficher une invite et obtenir une rponse con- ask forme certains critres. Afficher une roue tournante reprsentant une progression. Appliquer rsh(1) une temporisation plus courte. Afficher une arborescence de rpertoires avec tree loccupation du disque en blocs de 1k. Afficher une reprsentation graphique dune tree arborescence de rpertoires. Afficher une reprsentation graphique dune tree arborescence de rpertoires. Un serveur web en bash ! Afficher le contenu de la barre de titre de xterm. muler printf (obsolte puisque printf est dsormais une commande interne de bash). Exemples de fichiers de dmarrage. Quelques alias utiles (crits par Fox).

./scripts/nohup.bash ./scripts/precedence ./scripts/randomcard.bash ./scripts/README ./scripts/scrollbar ./scripts/scrollbar2 ./scripts/self-repro ./scripts/showperm.bash ./scripts/shprompt ./scripts/spin.bash ./scripts/timeout ./scripts/vtree2 ./scripts/vtree3 ./scripts/vtree3a ./scripts/websrv.sh ./scripts/xterm_title ./scripts/zprintf

./startup-files ./startup-files/Bash_aliases

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Fichiers de dmarrage
Tableau B-1. Chemins des exemples de bash version 3.1 et ultrieure (suite)
Chemin
./startup-files/Bash_profile ./startup-files/bash-profile ./startup-files/bashrc ./startup-files/Bashrc.bfox ./startup-files/README ./startup-files/apple ./startup-files/apple/aliases ./startup-files/apple/ bash.defaults

567

Description
Fichier de dmarrage pour un shell bash douverture de session (crit par Fox). Fichier de dmarrage pour un shell bash douverture de session (crit par Ramey). Fichier init pour le Bourne Again Shell (crit par Ramey). Fichier init pour le Bourne Again Shell (crit par Fox). README. Exemples de fichiers de dmarrage Mac OS X. Alias pour Mac OS X. 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 ./startup-files/apple/logout ./startup-files/apple/rc ./startup-files/apple/README Enveloppe douverture de session. Enveloppe de fermeture de session. Fichier de configuration pour le Bourne Again Shell. README.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 $personne "$personne" \$personne `$personne' "'$personne'" ~alice "~alice" `~alice' Valeur chapelier chapelier $personne $personne chapelier /home/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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

578
N scripts/bonjour No conflicts created by this import

Annexe D Gestion de versions

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 File: /tmp/cvsY1xcKa

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

CVS
/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..."

581

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

584
A scripts/tronc A scripts/tronc/hello Rvision 1 extraite. /home/jp$ cd scripts

Annexe D Gestion de versions

/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 /home/jp/scripts/tronc$ svn status M bonjour /home/jp/scripts/tronc$ svn update la rvision 1.

. bonjour

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Subversion
/home/jp/scripts/tronc$ svn st ? mcd M bonjour /home/jp/scripts/tronc$ svn add mcd A mcd

585

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Subversion
#!/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..."

587

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

RCS
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

589

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

RCS
drwxr-xr-x -r--r--r-2 jp jp 4.0K Jul 20 02:46 RCS/ 1 jp jp 63 Jul 20 02:45 bonjour

591

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

RCS
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.

593

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

596

Annexe D Gestion de versions

Accder ces fonctionnalits


Tableau D-1. Fonctions des logiciels de traitement de texte
Fonctionnalit Comparaison de documents Suivi des modifications Versions Writer diter diter Fichier Word Comparer le document Outils Comparaison et fusion de documents Modifications Versions Outils Fichier Suivi des modifications Versions

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

600
Tableau E-1. Fonctionnalits configurables de bash
Fonctionnalit alias arith-for-command array-variables bang-history brace-expansion command-timing cond-command cond-regexp Description Prise en charge des alias.

Annexe E Compiler bash

Prise en charge de lautre forme de la commande for qui se comporte comme linstruction for du langage C. Prise en charge des tableaux une dimension. Expansion et modification de lhistorique comme dans le shell C. Dveloppement des accolades. Prise en charge de la commande time. Prise en charge de la commande conditionnelle [[. Prise en charge de la correspondance des expressions rgulires POSIX en utilisant loprateur binaire =~ dans la commande conditionnelle [[. Prise en charge des commandes pushd, popd et dirs pour la manipulation des rpertoires. Activation de lexcution dune commande interne avec la commande builtin, mme dans le cas o elle a t dsactive par enable -n. Prise en charge de ((...)). Prise en charge de la commande interne help. Historique via les commandes fc et history. Contrle des tches laide de fg, bg et jobs si le systme dexploitation le permet. Prise en charge des caractres multioctets si le systme dexploitation le permet. Gestion spciale des noms de fichiers de la forme /dev/tcp/HTE/PORT et /dev/udp/HTE/PORT lorsquils sont employs dans les redirections. Activation de la substitution de processus si elle est accepte par le systme dexploitation.

directory-stack disabled-builtins

dparen-arithmetic help-builtin history job-control multibyte net-redirections

process-substitution

prompt-string-decoding Activation de lchappement des caractres dans PS1, PS2, PS3 et PS4. progcomp readline restricted select Fonctionnalits de compltion programmable. Si readline nest pas active, cette option na aucun effet. Fonctionnalits ddition et dhistorique readline. Prise en charge du shell restreint, de loption -r du shell et de rbash. La construction select.

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Contenu de larchive
Tableau E-1. Fonctionnalits configurables de bash (suite)
Fonctionnalit usg-echo-default xpg-echo-default Description

601

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

$* (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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Index
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

607

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

608
~/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

Index
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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

612
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

Index
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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

614
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

Index
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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

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>

bash Le livre de recettes

616

Index
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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Index
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

619
$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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 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

Index

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Index
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

621
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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

622
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

Index

P
-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

O
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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

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>

bash Le livre de recettes

624
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

Index
$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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

626
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]

Index
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>

bash Le livre de recettes

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]

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>

bash Le livre de recettes

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

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

Index
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

631
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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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 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

Index

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

634
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

Index
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

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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

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

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

636
VMware 338 console base sur VNC 339 VMware Player 339 VMware Server 339 vrai/faux, recherches 152

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

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

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
$x, ne pas utiliser 90 voir aussi $i

[05/03/08]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

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]

Elodie FRITSCH <elodie.fritsch@total.com>

bash Le livre de recettes

You might also like