2008 - Eyrolles - Shells Linux Et Unix Par La Pratique

Embed Size (px)

Citation preview

ShellsLinux et Unixpar la pratique

Christophe

Blaess

Linux et Unix

Shells

par la pratique

CHEZ LE MME DITEUR C. Blaess. Programmation systme en C sous Linux. N11054, 2002, 932 pages. D. Taylor. 100 scripts shell Unix. N11483, 2004, 366 pages. D. Taylor. Unix shell. N11147, 2002, 350 pages. M. KraffT, adapt par R. HerTzog et R. Mas, dir. N. MaKarviTcH. Debian. Administration et configuration avances. N11904, 2006, 674 pages. R. HerTzog, C. Le Bars, R. Mas. Debian. GNU/Linux. N11639, 2005, 298 pages I. HurBain. Mmento Unix/Linux. N11954, 2006, 14 pages. J.-F. BoucHaudy. Linux Administration Tome 1. N12037, 2006, 200 pages. J.-F. BoucHaudy. Linux Administration Tome 2. N12154, 2007, 400 pages. J.-F. BoucHaudy, G. gouBeT. Linux Administration (format semi-poche). N12074, 2007, 800 pages. s. Blondeel, d. carTron, J. risi. Dbuter sous Linux avec Mandriva. N11689, 2006, 530 pages. B. Caccinolo, L. DricoT, J. MarKoll. Ubuntu. Une distribution Linux facile utiliser. N11608, 2006, 360 pages. P. cegielsKi. Conception des systmes dexploitation - Le cas Linux. N11360, 2003, 606 pages. J.-F. BoucHaudy. TCP/IP sous Linux. N11369, 2003, 866 pages. B. BouTHerin, B. delaunay. Scuriser un rseau Linux (3e dition). N11960, 2007, 250 pages. V. sTanfield, r.W. sMiTH. Linux - Guide de ladministrateur. N11263, 2003, 654 pages. B. HaTcH, J. lee, g. KurTz. Halte aux hackers Linux. N25487, 2003, 660 pages. C. Aulds. Apache 2.0 - Guide de ladministrateur Linux. N11264, 2003, 612 pages. C. HunT. Serveurs rseau Linux. N11229, 2003, 648 pages. P. ficHeux. Linux embarqu (2e dition). N11674, 2005, 330 pages.

Linux et Unix

Shells

par la pratique

Christophe

Blaess

DITIONS EYROLLES 61, bd Saint-Germain 75240 Paris Cedex 05 www.editions-eyrolles.com

Le code de la proprit intellectuelle du 1er juillet 1992 interdit en effet expressment la photocopie usage collectif sans autorisation des ayants droit. Or, cette pratique sest gnralise notamment dans les tablissements denseignement, provoquant une baisse brutale des achats de livres, au point que la possibilit mme pour les auteurs de crer des uvres nouvelles et de les faire diter correctement est aujourdhui menace. En application de la loi du 11 mars 1957, il est interdit de reproduire intgralement ou partiellement le prsent ouvrage, sur quelque support que ce soit, sans autorisation de lditeur ou du Centre Franais dExploitation du Droit de Copie, 20, rue des Grands-Augustins, 75006 Paris. Groupe Eyrolles, 2008, ISBN : 978-2-212-12273-2

Avant-proposSur les systmes Linux et Unix actuels, lutilisateur est gnralement confront en premier lieu un environnement graphique disposant de navigateurs Internet, doutils graphiques pour parcourir les rpertoires et visualiser le contenu des chiers, dapplications pour la bureautique, de jeux, etc. Le shell ne constitue plus ncessairement le premier contact entre lutilisateur et le systme. Pourtant il sagit toujours dun passage oblig pour qui veut matriser et administrer correctement une machine Linux ou Unix. Le shell est tout dabord une interface efcace pour passer des ordres ou des commandes au systme. Il est plus rapide demployer une ligne comme$ cp /tmp/fic-0* /home/user/test/

que de lancer un gestionnaire de chiers, se placer dans le rpertoire source, slectionner les chiers intressants, utiliser la commande Copier, se dplacer dans le rpertoire destination et utiliser la commande Coller. Hormis laspect defcacit et de rapidit des commandes, le shell est un outil extrmement puissant puisquil permet de programmer des actions excutes intelligemment et automatiquement dans de nombreuses situations : dmarrage du systme (boot), tches administratives, lancement dapplication, analyse de chiers journaux, etc. Nous verrons dans ce livre quil est galement possible dcrire des scripts shell pour programmer de vritables petites applications utiles au quotidien et facilement personnalises par lutilisateur. Le langage de programmation du shell est assez ardu, peu intuitif et peu tolrant, aussi conseillerai-je au lecteur de mettre le plus vite possible ses connaissances en pratique, en faisant tourner les exercices et les exemples, en les modiant, en les personnalisant. Le code des exemples, des exercices corrigs et des scripts supplmentaires est disponible ladesse Web suivante : http://www.blaess.fr/christophe. Je tiens remercier tout ceux qui mont aid rdiger ce livre. Outre le soutien de mes proches pour mnager le temps ncessaire sa rdaction, je voudrais insister sur la qualit et la pertinence des remarques concernant mes prcdents ouvrages sur les scripts qui mont permis denrichir celui-ci. Je remercie pour cela Eric Berthomier, Laurent et Pierre Bourquard, Yannick Cadin, Michel Llibre, Franois Micaux, Davy NGuyen et bien dautres.

Table des matiresAvant-propos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .CHAPITRE 1

V

Principes des scripts Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Le shell Unix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Pourquoi crire un script shell ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Outils ncessaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1 2 4 5 5 6 7 9 11 11

Excution dun script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Invocation de linterprteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Appel direct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ligne shebang. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .CHAPITRE 2

Programmation Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Premier aperu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Premier script, rm_secure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Analyse dtaille . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Performances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exemple dexcution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13 14 14 16 23 24 26 26

VIII

Shells Linux et Unix par la pratique

CHAPITRE 3

valuation dexpressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Prcisions sur loprateur $ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29 11 13 26 29 30 41 41 45 49 50 51 51 53 54 57 57

Calcul arithmtique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Invocation de commande . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Portes et attributs des variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Paramtres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Paramtres positionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Paramtres spciaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Protection des expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Protection par le caractre backslash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Protection par apostrophes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Protection par guillemets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . valuation explicite dune expression . . . . . . . . . . . . . . . . . . . . . . . . . . . Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .CHAPITRE 4

lments de programmation shell . . . . . . . . . . . . . . . . . . . . . . . . . .Commandes et code de retour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Commande simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pipelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Listes de pipelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Commandes composes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

77 77 77 79 81 89 90 90 91 100 104 104

Redirections dentres-sorties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Entres-sorties standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Redirection des entres et sorties standards . . . . . . . . . . . . . . . . . . . . . . . . Redirections avances. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Structures de contrle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Slection dinstructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Table des matires

IX112 120 127 127

Itrations dinstructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .CHAPITRE 5

Commandes, variables et utilitaires systme . . . . . . . . . . . . . . .Commandes internes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Comportement du shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Excution des scripts et commandes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interactions avec le systme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Arguments en ligne de commande . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Variables internes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

131 132 132 133 136 141 147 150 153 153

Commandes externes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .CHAPITRE 6

Programmation shell avance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Processus ls, paralllisme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Arrire-plan et dmons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Signaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Envoi dun signal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rception dun signal. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Attente de signaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

155 155 160 163 164 165 166 167 170 171 172 174 174 175 176

Communication entre processus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Entres-sorties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .tee . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xargs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Interface utilisateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .stty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . tput . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . dialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

X

Shells Linux et Unix par la pratique

Dboguer un script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Virgule ottante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .CHAPITRE 7

176 177 178

Expressions rgulires Grep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Expressions rgulires simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Expressions rationnelles tendues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

179 179 180 189 190 192 193 193

Outil grep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Recherche rcursive avec nd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .CHAPITRE 8

Sed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Utilisation de Sed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fonctionnement de Sed. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Commandes Sed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

195 195 196 197 198 201 210 210

Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .CHAPITRE 9

Awk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Fonctionnement de Awk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Les motifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Les actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Les variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

213 213 214 215 217 217 217 220

Enregistrements et champs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Les enregistrements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Les champs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Table des matires

XI224 226 227 232 232

Structures de contrle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Retour sur les afchages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .CHAPITRE 10

Bonne criture dun script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Prsentation gnrale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Les variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Gestion des erreurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Les fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .ANNEXE A

233 233 235 236 239 240 241

Solutions des exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Chapitre 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chapitre 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chapitre 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chapitre 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chapitre 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chapitre 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chapitre 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .ANNEXE B

243 243 244 245 248 250 252 254

Bibliographie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Livres et articles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sites de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Norme Single UNIX Specication Version 3 . . . . . . . . . . . . . . . . . . . . . . Bash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

255 255 256 256 256

XII

Shells Linux et Unix par la pratique

Korn shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pdksh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tcsh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zsh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .INDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

256 256 257 257 257 259

1Principes des scripts ShellAvant de commencer notre tude des scripts shell pour Unix et Linux, jaimerais prciser quelques lments de vocabulaire que jemploierai couramment et qui ne sont pas toujours trs intuitifs pour le lecteur profane. Tout dabord, nous tudierons la programmation de scripts. Un script est chier contenant une srie dordres que lon va soumettre un programme externe pour quil les excute. Ce programme est appel interprteur de commandes. Il existe de nombreux interprteurs de commandes. Naturellement, le shell en fait partie, tout comme certains outils tels que Sed et Awk que nous verrons ultrieurement, ainsi que dautres langages tels que Perl, Python, Tcl/Tk, Ruby, etc. Ces langages sont dits interprts, par opposition aux langages compils (comme C, C++, Fortran, Ada, etc.). Leurs principales diffrences sont les suivantes : Aprs lcriture dun chier script, il est possible de le soumettre directement linterprteur de commandes, tandis quun code source crit en langage compil doit tre traduit en instructions de code machine comprhensibles pour le processeur. Cette tape de compilation ncessite plusieurs outils et peut parfois savrer longue. Le code compil tant directement compris par le processeur du systme, son excution est trs rapide, alors quun script doit tre interprt dynamiquement, ce qui ralentit sensiblement lexcution. Le chier excutable issu dune compilation est souvent volumineux et nest utilisable que sur un seul type de processeur et un seul systme dexploitation. linverse, un chier script est gnralement assez rduit et directement portable sur dautres processeurs ou dautres systmes dexploitation pour peu que linterprteur de commandes correspondant soit disponible.

2

Shells Linux et Unix par la pratique

Un chier compil est incomprhensible par un lecteur humain. Il nest pas possible den retrouver le code source. Cela peut garantir le secret commercial dun logiciel. Inversement, un chier script est directement lisible et modiable, et peut contenir sa propre documentation sous forme de commentaires, ce qui est intressant dans le cadre des logiciels libres.

Le shell UnixUnix est un systme dexploitation n au dbut des annes 1970, et qui se dcline de nos jours sous diffrentes formes : les versions commerciales dUnix, telles que Solaris (Sun), AIX (IBM), HP-UX, etc. ; les versions libres de systmes clonant Unix (on parle de systmes Unix-like), dont le plus connu est Linux, mais il existe aussi des variantes comme FreeBSD, NetBSD, Hurd, etc. Le shell fait partie intgrante dUnix depuis les dbuts de celui-ci en 1971. On peut dailleurs en trouver une prsentation simplie dans le clbre article [Ritchie 1974] The UNIX Time-Sharing System qui dcrivait les premires versions dUnix. Le shell est avant tout un interprteur de commandes, charg de lire les ordres que lutilisateur saisit au clavier, de les analyser, et dexcuter les commandes correspondantes. Curieusement, les tubes de communication (pipes) permettant de faire circuler des donnes de processus en processus et donnant toute leur puissance aux scripts shell, ne sont apparus que plus tard, n 1972. Le premier shell fut crit par Steve Bourne et le chier excutable correspondant tait traditionnellement /bin/sh. Il permettait dcrire de vritables scripts complets, avec des structures de contrle performantes. Toutefois, son utilisation quotidienne de manire interactive pchait quelque peu par manque dergonomie. Un nouveau shell dit shell C fut donc mis au point par William Joy luniversit de Berkeley. Cet outil fut ofciellement introduit dans certaines distributions Unix en 1978, et prsent dans un article clbre [Joy 1978]. Le chier excutable tait /bin/csh. Linterface utilisateur tait beaucoup plus agrable, grant un historique des commandes, des alias, etc. Il ne faut pas oublier que lutilisateur dUnix ne disposait cette poque que dun terminal en mode texte, et que lintroduction du contrle des jobs, par exemple, augmentait considrablement la productivit en permettant de basculer facilement dapplication en application. Hlas, le shell C fut dot dun langage de programmation ressemblant quelque peu au langage C, mais dont limplmentation tait fortement bogue. En dpit des corrections qui y furent apportes, le comportement des scripts pour shell C ntait pas satisfaisant. La plupart des utilisateurs dcidrent alors demployer le shell C pour laccs interactif au systme, et le shell Bourne pour lcriture de scripts automatiss. On remarquera par exemple que louvrage [Dubois 95] Using csh & tcsh naborde pas la programmation de scripts, car lauteur considre que dautres shells sont plus appropris pour cette tche.

Principes des scripts Shell CHAPITRE 1

3

En 1983, David G. Korn, travaillant aux laboratoires AT&T Bell, dveloppa un nouveau shell, nomm /bin/ksh (Korn Shell), dont le but tait de proposer la fois les qualits interactives du shell C et lefcacit des scripts du shell Bourne. Linterface utilisateur, par exemple, proposait la fois un mode ddition vi et un mode Emacs. Le shell Korn volua rapidement, et de nouvelles versions en furent proposes en 1986, puis en 1988 et enn en 1993. Le shell Korn tait uniquement disponible comme logiciel commercial, vendu par AT&T, ce que certains utilisateurs lui reprochaient. Cette politique a t modie le 1er mars 2000, puisque le shell Korn 1993 est prsent disponible sous licence open source. Paralllement au dploiement du shell Korn, la ligne des shells C connut un nouveau regain dintrt avec la diffusion de Tcsh, qui essayait de copier certaines fonctionnalits dinterface dun ancien systme dexploitation pour PDP-10, le Tenex. Ce shell offrait galement de nombreuses amliorations et corrections des dfauts de Csh. Nous le retrouvons de nos jours sur les systmes Linux, entre autres. Paralllement lvolution des Unix et des shells commerciaux , on assista dans les annes 1980 la perce des logiciels libres, et plus particulirement du projet GNU (acronyme rcursif de Gnu is Not Unix) destin cloner le systme Unix, ce qui permettra ultrieurement lapparition des distributions GNU/Linux. La FSF (Free Software Fundation), fonde en 1985 par Richard M. Stallman pour dvelopper le projet GNU, avait besoin dun interprteur de commandes libre et performant. Un programmeur, Brian Fox, fut embauch pour dvelopper ce shell. Ce projet, repris par la suite par Chet Ramey, donna naissance au fameux shell Bash, que lon trouve demble sur les distributions Linux. Bash est lacronyme de Bourne Again Shell, revendiquant ainsi sa liation forte au shell sh original. Dun autre ct, Bash a aussi intgr de nombreuses fonctionnalits provenant du shell Korn, et mme de Tcsh. Il est ainsi devenu un outil trs puissant, que la plupart des utilisateurs de Linux emploient comme shell de connexion.Libre ou ? Faute de mieux, nous opposerons les termes libres et commerciaux concernant les logiciels ou les implmentations dUnix. Cette distinction nest pas parfaite, pour de nombreuses raisons, mais elle est la plus intuitive et la plus proche de la ralit conomique des produits disponibles.

Avant la mise sous licence libre du shell Korn, les systmes libres dsireux de disposer dun shell de ce type utilisaient une variante gratuite : le shell Pdksh (Public Domain Korn Shell) crit lorigine par Eric Gisin. la n des annes 1980, il existait une plthore de systmes compatibles Unix ou prtendument compatibles Unix qui implmentaient chacun de nouvelles fonctionnalits par rapport au systme Unix original. Chaque fabricant de matriel, chaque diteur de logiciels dsirait disposer de sa propre version compatible Unix, et la situation tait devenue catastrophique en ce qui concerne la portabilit des applications.

4

Shells Linux et Unix par la pratique

Mme les commandes shell simples pouvaient disposer de variantes diffrentes sur chaque systme. Il fut donc ncessaire duniformiser le paysage propos par toutes ces versions dUnix. Une norme fut propose par lIEEE : Posix. Elle dcrivait linterface entre le cur du systme dexploitation (le noyau) et les applications, ainsi que le comportement dun certain nombre doutils systme dont le shell. Ce standard ntait pas consultable librement, et sa redistribution tait prohibe, aussi les utilisateurs lui prfrrent une autre norme, crite par lOpen Group (association dditeurs de systmes compatibles Unix) et sensiblement quivalente : Single Unix Specication (S.U.S). De nos jours, la version 3 de ce standard (abrg habituellement en SUSv3) a intgr le contenu de la norme Posix. Pour sassurer de la portabilit dune fonction propose par le shell ou dune option offerte par une commande, on pourra donc se reporter vers SUSv3, disponible aprs avoir rempli un formulaire rapide sur :http://www.unix.org/single_unix_specication/.

Pourquoi crire un script shell ?Lcriture de scripts shell peut rpondre plusieurs besoins diffrents. Je voudrais citer quelques domaines dapplications, pour donner une ide du panorama couvert par les scripts shell usuels : Les plus simples dentre eux serviront simplement lancer quelques commandes disposant doptions complexes, et quon dsire employer rgulirement sans avoir se reporter sans cesse leur documentation (pages de manuel). Les scripts dinitialisation de boot du systme, permettent dnumrer les priphriques disponibles, et de les initialiser, de prparer les systmes de chiers, les partitions, et de congurer les communications et les services rseau. Ils sont normalement livrs avec le systme dexploitation, mais ladministrateur expriment doit parfois intervenir dans ces scripts (souvent longs et fastidieux) pour personnaliser un serveur. Certaines applications spciques (logiciels mtier ) ncessitent un paramtrage complexe, et des scripts shell sont employs pour assurer la gestion de congurations, la prparation des rpertoires et des chiers temporaires, etc. La supervision dun parc informatique rclame des tches automatises pour vrier ltat des systmes (utilisation de la mmoire et des espaces disque, antivirus...) et assurer des tches de maintenance priodique (effacement des chiers temporaires, rotation des chiers de traces...). De nombreux serveurs utilisent une interface constitue de scripts shell pour transmettre des requtes SQL au logiciel de base de donnes (Oracle, MySQL, etc.) Pour assurer lexploitation de serveurs rseau ou de machines industrielles, ladministrateur doit exploiter la sortie de certaines commandes de supervision, et les traces

Principes des scripts Shell CHAPITRE 1

5

enregistres dans des chiers de journalisation (log le). Pour cela des scripts shell enrichis de commandes Awk permettront dextraire facilement des informations statistiques. Naturellement, il est possible dcrire des scripts shell pour dautres domaines dapplication (traitement automatique du contenu de chiers de texte, calcul, menus dinterface utilisateur, etc.), mais les exemples dutilisation les plus courants relvent plutt de ladministration du systme.

Outils ncessairesLe but de ce livre est de permettre au lecteur de raliser rapidement des scripts utiles, complets et robustes. Nous ne prtendons ni lexhaustivit dun manuel de rfrence, ni au niveau de dtail quun ouvrage de programmation avance pourrait offrir. Pour les lecteurs dsireux dapprofondir leurs connaissances sur un langage particulier, nous prsenterons des rfrences complmentaires en bibliographie. Nous nous intresserons la programmation de scripts compatibles SUSv3 , autrement dit des scripts utilisables tant sur systmes Unix commerciaux (employant le shell Ksh) que sur les systmes libres comme Linux (avec le shell Bash). Dans certains scripts proposs en exemple ou en exercice, nous devrons faire appel certaines extensions GNU, cest--dire des options dutilitaires systme non documentes dans SUSv3, ajoutes dans leur version GNU. Ce livre se voulant le plus interactif possible, il est important que le lecteur puisse saisir et excuter les exemples proposs, et tlcharger le code source des scripts sur le site personnel de lauteur :http://www.blaess.fr/christophe

Le lecteur nayant pas daccs immdiat un systme Unix ou compatible, mais disposant dune machine fonctionnant avec Windows, pourra se tourner vers le projet Cygwin (voir http://www.cygwin.com) qui propose un portage des outils GNU (donc de Bash) sur ce systme dexploitation. Un second outil sera indispensable : un diteur de texte pour saisir et modier le contenu des scripts. Il existe une plthore dditeurs sur chaque systme, les plus traditionnels sur Unix tant vi et Emacs (existant dans des versions plus ou moins conviviales et esthtiques), mais on peut galement citer Nedit, Gedit, Kwrite, etc.

Excution dun scriptAvant de rentrer dans le dtail des langages de programmation par scripts, consacrons quelques pages aux mthodes possibles pour que soit excut un tel programme. Il nest pas indispensable de comprendre en dtail les interactions entre le shell, le noyau et linterprteur pour faire excuter un script, mais cela permet de bien comprendre le rle de la premire ligne que nous retrouverons dans tous nos chiers.

6

Shells Linux et Unix par la pratique

tant bien entendu quun script ne peut pas tre excut dune manire autonome, mais quil ncessite la prsence dun interprteur pour le faire fonctionner, plusieurs mthodes peuvent tre invoques pour lancer un tel programme.

Invocation de linterprteurPour tester cela, nous allons crer un premier script extrmement simple. Utilisez lditeur de texte de votre choix pour crer un chier nomm essai.sh contenant uniquement la ligne suivante :essai.sh: echo "Ceci est mon premier essai"

La commande echo du shell doit simplement afcher la chane transmise sur sa ligne de commande. prsent nous allons essayer de lexcuter en le prcdant, sur la ligne de commande, de lappel du shell. Le symbole $, prsent en dbut de ligne ci-dessous, correspond au symbole dinvite (prompt) du shell et ne doit naturellement pas tre saisi :$ sh essai.sh Ceci est mon premier essai $

Cela fonctionne bien. Remarquez que le sufxe .sh ajout la n du nom du script na aucune importance ; il ne sagit que dune information pour lutilisateur. Le systme Unix ne tient aucun compte des sufxes ventuels des noms de chiers. Par exemple, renommons-le et ressayons :$ mv essai.sh essai $ sh essai Ceci est mon premier essai $

Les lecteurs les plus intrpides qui se seront aventurs nommer le chier test plutt que essai pourront avoir une mauvaise surprise ici, avec un message derreur du type :$ sh test /usr/bin/test: /usr/bin/test: cannot execute binary file $

Cela est d la prsence sur leur systme dun autre chier excutable nomm test, mais qui nest pas un script shell. Nous en reparlerons plus loin.

Principes des scripts Shell CHAPITRE 1

7

Appel directPlutt que dinvoquer linterprteur suivi du nom du chier, nous prfrerions appeler directement le script, comme sil sagissait dune commande habituelle. Essayons donc dappeler directement notre script essai:$ essai ksh: essai: non trouv [Aucun fichier ou rpertoire de ce type]

Le message derreur variera suivant le shell interactif que vous utilisez, mais le contenu sera en substance identique : le shell dplore de ne pouvoir trouver le chier essai. Ceci est tout fait normal. Lorsque nous invoquons une commande Unix (par exemple, ls), le systme devra trouver un chier excutable de ce nom (/bin/ls en loccurrence). Mais il est impossible de parcourir tous les rpertoires de tous les disques pour rechercher ce chier, le temps de rponse serait horriblement long ! Pour amliorer les performances, le systme Unix ne recherche les chiers implmentant les commandes que dans un nombre restreint de rpertoires. Ceux-ci sont numrs dans la variable denvironnement PATH, que nous pouvons consulter. Pour cela, il faudra faire prcder le nom PATH dun caractre $, comme nous le dtaillerons plus tard, et bien respecter le nom en majuscules. Examinons le contenu de la variable :$ echo $PATH /bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/home/cpb/bin $

Nous voyons que plusieurs rpertoires sont indiqus, spars par des deux-points. Le rpertoire dans lequel nous nous trouvons actuellement nest pas mentionn, donc le systme ne vient pas y chercher le chier essai.Portabilit Nous sommes ici sur un systme Linux, et lemplacement exact des rpertoires peut diffrer suivant les versions dUnix. Toutefois, on retrouvera toujours une organisation approchante.

Pour que le shell puisse trouver notre chier essai, plusieurs possibilits soffrent nous. Il est possible de dplacer le script dans un des rpertoires du PATH. Si nous avions cr un script utile pour tous les utilisateurs dUnix, il serait en effet envisageable de le placer dans /usr/bin. Si ce script sadressait uniquement aux utilisateurs de notre systme, le rpertoire /usr/local/bin serait plus appropri. Enn, si le script tait rserv notre usage personnel, le sous-rpertoire bin/ situ dans notre rpertoire personnel conviendrait mieux. Toutefois ceci suppose que le script soit parfaitement au point. Pendant la priode de cration et de corrections initiales, il vaut mieux le conserver dans un rpertoire de travail spcique.

8

Shells Linux et Unix par la pratique

Une autre approche consiste modier notre variable PATH pour lui ajouter un point (.) qui reprsente toujours le rpertoire courant. Pour des raisons de scurit, il faut toujours placer ce point en dernire position dans la variable PATH (ceci sera tudi en dtail dans les exercices en n de chapitre). On pourra excuter la commande :$ PATH=$PATH:.

avant dappeler essai, voire la placer dans le chier dinitialisation (chier profile) de notre shell. Attention toutefois, certains problmes de scurit peuvent se poser si vous travaillez sur un systme ouvert au public. La troisime possibilit la plus contraignante, mais la plus sre consiste indiquer au systme le rpertoire o se trouve le chier chaque fois quon linvoque. Ceci sobtient aisment si le chier se trouve dans le rpertoire courant en utilisant lappel :$ ./essai

Malheureusement, cela ne fonctionne pas beaucoup mieux :$ ./essai ksh: ./essai: ne peut pas excuter [Permission non accorde] $

Le script ne sexcute pas plus quavant, mais le message derreur a chang. Ceci est d aux permissions accordes pour ce chier, et que lon peut observer avec loption -l de ls:$ ls -l essai -rw-r--r-- 1 cpb users 34 sep 3 14:08 essai $

La premire colonne dcrit le type de chier et les permissions concernant sa manipulation : Le premier tiret - correspond un chier normal (d pour un rpertoire, l pour un lien symbolique, etc.). Les trois lettres suivantes indiquent que le propritaire cpb du chier a les droits de lecture (r) et dcriture (w) sur son chier, mais labsence de lettre x, remplace ici par un tiret, signie que le propritaire ne peut pas excuter ce chier. Cest justement notre problme. Les trois lettres r-- suivantes dcrivent les droits fournis aux autres utilisateurs appartenant au mme groupe que le chier (users). Seule la lecture du contenu du chier sera possible. Il ne sera pas possible de lexcuter et de le modier.

Principes des scripts Shell CHAPITRE 1

9

Enn les trois dernires lettres indiquent les permissions accordes tous les autres utilisateurs du systme (r-- lecture seulement). Le chier ntant pas excutable, il est impossible de le lancer. Pour modier les permissions dun chier, il faut utiliser la commande chmod(1).Notation Dans toutes les descriptions techniques Unix, une notation comme chmod(1) signie quon fait rfrence un lment nomm chmod dont la documentation se situe dans la section 1 du manuel. On obtiendra donc des informations supplmentaires en appelant la commande man 1 chmod.

Il y a plusieurs types doptions possibles pour chmod, la plus parlante est srement celle-ci :$ chmod +x essai $ ls -l essai -rwxr-xr-x 1 cpb users 34 sep 3 14:08 essai $

Loption +x de chmod ajoute lautorisation dexcution pour tous les types dutilisateurs. Vrions que notre script fonctionne :$ ./essai Ceci est mon premier essai $

Parfait !

Ligne shebangMarquons toutefois une brve pause, et rchissons un instant ce que nous avons ralis. Nous avons cr le chier essai contenant une seule ligne afchant un message ; nous avons rendu le chier excutable avec chmod; puis nous lavons lanc en utilisant la notation ./essai. Nous savons que ce chier doit tre interprt par un shell, cest--dire quun shell disponible sur le systme (sh, bash, ksh...) doit lire le script et traduire son contenu ligne ligne. Mais comment le systme sait-il que ce chier doit tre interprt par un shell ? Comment sait-il quil sagit dun script shell et non dun script Sed, Awk, Perl, ou autre ? Comment se fait lassociation entre notre chier et le shell du systme ? En ralit, nous navons rien prcis, et si le script fonctionne quand mme, cest uniquement grce un comportement par dfaut dans le cas o cette information est absente.

10

Shells Linux et Unix par la pratique

Pour prciser linterprteur employer, on utilise le principe de la ligne shebang (contraction de shell et de bang point dexclamation en anglais). Lorsque le noyau saperoit que les deux premiers caractres du chier sont #!, il considre que tout le reste de la ligne reprsente le nom de linterprteur utiliser. Et si lon demande excuter le chier mon_script.sh crit ainsi :mon_script.sh : #! /bin/ksh echo "Voici un second script

le systme dexploitation traduira linvocation :$ ./mon_script.sh

en :$ /bin/ksh ./mon_script.sh

Le shell considre que lorsquil rencontre un caractre #, il doit ignorer toute la suite de la ligne. Cest ainsi quon ajoute des commentaires dans un script shell. Aussi le shell (ksh ici) qui va lire le script ignorera-t-il cette premire ligne. Attention, les caractres # et ! doivent tre exactement le premier et le second du chier ; il ne doivent tre prcds daucune espace, tabulation ou ligne blanche. Insrer une ligne shebang dans un script shell prsente plusieurs avantages : Mme si un script shell peut fonctionner sans cette ligne, sa prsence est gage de comportement correct, linterprteur sera choisi sans ambigut. En outre, si le script est lanc directement par une application (environnement graphique, par exemple) et non par un shell, seule la prsence de la ligne shebang garantira le bon dmarrage du script. La ligne shebang dun script shell fait gnralement appel /bin/sh comme interprteur, mais un script crit pour le langage Awk pourra utiliser #! /bin/awk -f, par exemple, en incluant une option -f sur la ligne de commande de linterprteur. Si le shell employ pour interprter les scripts est souvent /bin/sh, il arrive, sur certains systmes (Solaris par exemple), que celui-ci soit trop ancien, et que lon prfre invoquer un shell plus rcent par exemple /bin/ksh. Enn, le fait de placer cette premire ligne est dj un lment de documentation du script. La personne qui devra diter ce chier ultrieurement trouvera l une premire indication de son fonctionnement. Personnellement, lorsque je dois crire un script shell, mes doigts saisissent machinalement la ligne #!/bin/sh, pendant que je rchis aux premires lignes que jajouterai en dessous. Nous dvelopperons ce thme concernant la bonne criture dun script dans un chapitre ultrieur.

Principes des scripts Shell CHAPITRE 1

11

ConclusionDans ce chapitre, nous avons dress un panorama rapide des shells disponibles sur la majeure partie des systmes Unix et Linux. Nous avons galement vu comment crer, rendre excutable et lancer un script shell. Retenons que la prsence de la premire ligne shebang du script sera un gage de qualit et de portabilit du script.

ExercicesVous trouverez dans les diffrents chapitres de ce livre quelques exercices destins vous entraner et vous perfectionner dans lcriture des scripts. Les solutions des exercices sont proposes en n de livre, dans lannexe A, et les scripts complets peuvent tre tlchargs sur le site de lauteur, ladresse suivante :http://www.blaess.fr/christophe

1.1 Prise en main du systme (facile)Identiez les shells disponibles sur votre systme, et dterminez lidentit du shell /bin/sh. Vriez galement les diteurs de texte proposs par votre environnement de travail, et familiarisez-vous avec celui qui vous semble le plus adapt.

1.2 Utilit de la variable PATH (facile)Pour prendre conscience de lutilit de la variable PATH, effacez-la ainsi :

$ PATH=Puis essayez quelques commandes :

$ cd /etc $ ls $ echo "Hello" $ cd /bin $ /bin/ls etc.Que se passe-t-il ? Pourquoi ? Comment y remdier ?

12

Shells Linux et Unix par la pratique

1.3 Rpertoire courant dans le PATH (plutt facile)Ajoutez le rpertoire . (point) la n de votre variable PATH de cette manire :

$ PATH=$PATH:.Essayez prsent de lancer le script essai.sh sans le faire prcder de ./. Cela fonctionne-t-il ?

1.4 Dangers associs au PATH (plutt difcile)crivez un petit script afchant un simple message, appelez-le ls (noubliez pas de le rendre excutable) et sauvegardez-le dans le rpertoire /tmp. Connectez-vous prsent avec une autre identit sur votre systme. Modiez votre variable

PATH pour quelle contienne le rpertoire courant en premire position. Allez prsent dans le rpertoire /tmp, et afchez la liste des chiers quil contient. Que se passe-t-il ?

2Programmation ShellAvant dentamer la programmation sous shell, rappelons la syntaxe lmentaire qui est utilise pour lancer des processus depuis la ligne de commande sous Unix et Linux, puisque nous emploierons galement ces symboles dans les scripts.Saisie SignicationLa commande est excute normalement ; le symbole dinvite sera afch lorsquelle se terminera. La commande est excute en arrire-plan, ce qui signie quelle na en principe pas accs au terminal. Le shell reprend donc la main immdiatement, et af che son symbole dinvite alors que la commande continue sexcuter en tche de fond. Le shell afche une ligne du type

commande commande &

[1] 2496indiquant le numro du job larrire-plan, suivi du PID (lidentiant de processus). Lorsque la commande se termine, le shell afchera une ligne

[1]+ commande > fichier commande >> fichier commande < fichier cmmnd_1 | cmmnd_2

Done commande

juste avant de proposer un nouveau symbole dinvite. La commande est excute, mais sa sortie standard est dirige vers le chier indiqu. Seule la sortie derreur safche lcran. La sortie standard est ajoute en n de chier sans en craser le contenu. La commande est excute, mais ses informations dentre seront lues depuis le chier qui est indiqu plutt que depuis le ter minal. Les deux commandes sont excutes simultanment, lentre standard de la seconde tant connecte par un tube (pipe) la sortie standard de la premire.

Nous tendrons ces possibilits ultrieurement, mais ces lments seront dj sufsants pour comprendre les premiers scripts tudis.

14

Shells Linux et Unix par la pratique

Premier aperuAvant dentrer dans le dtail de la syntaxe et des commandes pour le shell, nous allons tout dabord survoler un script complet, an de nous familiariser avec la structure des programmes shell. Ce script, dj assez important pour un premier exemple, est une variation sur un article que javais crit en mai 1996 pour le journal la ligne Linux Gazette, [Blaess 1996].

Premier script, rm_secureLide est de remplacer la commande rm normale (suppression de chiers et de rpertoires) par un script qui permette de rcuprer les chiers effacs malencontreusement. Il en existe des implmentations plus performantes, mais lavantage de ce script est dtre assez simple, facile installer et tudier. Nous allons lanalyser en dtail, dans son intgralit. Des numros ont t ajouts en dbut de ligne pour rfrence, mais ils ne font videmment pas partie du script.rm_secure.sh: 1 sauvegarde_rm=~/.rm_saved/ 2 3 function rm 4 { 5 local opt_force=0 6 local opt_interactive=0 7 local opt_recursive=0 8 local opt_verbose=0 9 local opt_empty=0 10 local opt_list=0 11 local opt_restore=0 12 local opt 13 14 OPTERR=0 15 # Analyse des arguments de la ligne de commande 16 while getopts ":dfirRvels-:" opt ; do 17 case $opt in 18 d ) ;; # ignore 19 f ) opt_force=1 ;; 20 i ) opt_interactive=1 ;; 21 r | R ) opt_recursive=1 ;; 22 e ) opt_empty=1 ;; 23 l ) opt_list=1 ;; 24 s ) opt_restore=1 ;; 25 v ) opt_verbose=1 ;; 26 - ) case $OPTARG in 27 directory ) ;; 28 force) opt_force=1 ;; 29 interactive ) opt_interactive=1 ;; 30 recursive ) opt_recursive=1 ;; 31 verbose ) opt_verbose=1 ;;

Programmation Shell CHAPITRE 2

15

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 74 75 76 77 78 79 80 81 82

help ) /bin/rm --help echo "rm_secure:" echo " -e --empty vider la corbeille" echo " -l --list voir les fichiers sauvs" echo " -s, --restore rcuprer des fichiers" return 0 ;; version ) /bin/rm --version echo "(rm_secure 1.2)" return 0 ;; empty ) opt_empty=1 ;; list ) opt_list=1 ;; restore ) opt_restore=1 ;; * ) echo "option illgale --$OPTARG" return 1;; esac ;; ? ) echo "option illgale -$OPTARG" return 1;; esac done shift $(($OPTIND - 1)) # Crer ventuellement le rpertoire if [ ! -d "$sauvegarde_rm" ] ; then mkdir "$sauvegarde_rm" fi # Vider la poubelle if [ $opt_empty -ne 0 ] ; then /bin/rm -rf "$sauvegarde_rm" return 0 fi # Liste des fichiers sauvs if [ $opt_list -ne 0 ] ; then ( cd "$sauvegarde_rm" ls -lRa * ) fi # Rcupration de fichiers if [ $opt_restore -ne 0 ] ; then while [ -n "$1" ] ; do mv "${sauvegarde_rm}/$1" . shift done return fi # Suppression de fichiers while [ -n "$1" ] ; do # Suppression interactive : interroger l'utilisateur if [ $opt_force -ne 1 ] && [ $opt_interactive -ne 0 ] then

16

Shells Linux et Unix par la pratique

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

local reponse echo -n "Dtruire $1 ? " read reponse if [ "$reponse" != "y" ] && [ "$reponse" != "Y" ] && [ "$reponse" != "o" ] && [ "$reponse" != "O" ] ; then shift continue fi fi if [ -d "$1" ] && [ $opt_recursive -eq 0 ] ; then # Les rpertoires ncessitent l'option rcursive shift continue fi if [ $opt_verbose -ne 0 ] ; then echo "Suppression $1" fi mv -f "$1" "${sauvegarde_rm}/" shift done } trap "/bin/rm -rf $sauvegarde_rm" EXIT

Lanalyse dtaille du script est un peu laborieuse, mais il est nettement prfrable dtudier un programme rel, complet et utilisable, quun exemple simpliste, construit uniquement pour illustrer les possibilits du shell. Si certaines parties semblent obscures, il ny a pas lieu de sinquiter : nous y reviendrons dans la prsentation des commandes et de la syntaxe.

Analyse dtailleExceptionnellement, ce script ne dbute pas par une ligne shebang introduite par #!. En effet, il nest pas conu pour tre excut dans un processus indpendant avec une commande comme ./rm_secure.sh, mais pour tre lu par une commande source ou . depuis un chier dinitialisation du shell (comme ~/.profile ou ~/.bashrc). Lorsquun script est appel ainsi . script, il est interprt directement par le shell en cours dexcution, sans lancer de nouvelle instance. Aussi les variables et fonctions dnies par ce script seront-elles disponibles mme aprs sa terminaison. Il ne faut pas confondre le point utilis ici pour sourcer un script, et le point reprsentant le rpertoire courant dans lappel ./script. Ce script dnit une fonction nomme rm, stendant des lignes 3 103. Le programme tant lu et interprt directement par le shell, et non par un processus ls, cette fonction sera disponible dans lenvironnement du shell qui vient de sinitialiser. Lorsquon appelle, depuis la ligne de saisie, un nom de commande comme rm, le shell va dabord contrler sil existe dans son environnement une fonction qui a ce nom. Sil nen

Programmation Shell CHAPITRE 2

17

trouve pas, il vriera sil sagit de lune de ses commandes internes (comme cd). En dernier ressort, il parcourra lensemble des rpertoires mentionns dans la variable denvironnement PATH la recherche dun chier excutable qui ait le nom indiqu. Naturellement, si la commande contient un chemin daccs (par exemple /bin/rm), il vite tout ce mcanisme et lance directement le chier dsir. Dans notre cas, nous dnissons une fonction ayant pour nom rm, qui sera donc invoque la place du chier /bin/rm habituel. La premire ligne du script dnit une variable qui contient le nom dun rpertoire vers lequel les chiers seront dplacs plutt que vritablement effacs. Des options la ligne de commande nous permettront dexaminer le contenu du rpertoire et de rcuprer des chiers. Il est vident que lutilisateur doit avoir un droit dcriture sur ce rpertoire. La conguration la plus intuitive consiste utiliser un rpertoire qui gure dj dans le rpertoire personnel de lutilisateur et de lui donner un nom qui commence par un point an dviter de le retrouver chaque invocation de ls. Nous voyons que laffectation dune variable se fait, avec le shell, simplement laide dune commande nom=valeur. Il est important de noter quil ne doit pas y avoir despace autour du signe gal. Vient ensuite la dclaration de la fonction. On emploie le mot-cl function suivi du nom de la routine, puis de son corps encadr par des accolades. Les lignes 5 12 dclarent des variables locales de la fonction. Ces variables serviront noter, lors de lanalyse de la ligne de commande, les diffrentes options indiques par lutilisateur. Les dclarations sont ici prcdes du mot-cl local, qui permet de ne les rendre visibles que dans notre fonction. Quand une fonction est, comme ici, destine rester durablement dans la mmoire du shell, il est important de ne pas polluer lenvironnement en laissant inutilement des variables apparatre en dehors de la routine o elles sont employes. Notre fonction rm accepte les mmes options la ligne de commande que la commande / bin/rm, et en ajoute trois nouvelles :Option SignicationIgnore Ne pas interroger lutilisateur Interroger lutilisateur avant de supprimer un chier Supprimer dune faon rcursive les rpertoires Afcher les noms des chiers avant de les supprimer Afcher une page daide Afcher le numro de version du programme Vider la corbeille de sauvegarde Voir le contenu de la corbeille Rcuprer un chier dans la corbeille

Provenance

-d ou --directory -f ou --force -i ou --interactive -r, -R, ou --recursive -v ou --verbose --help --version -e ou --empty -l ou --list -s ou --restore

/bin/rm /bin/rm /bin/rm /bin/rm /bin/rm /bin/rm /bin/rm rm_secure rm_secure rm_secure

18

Shells Linux et Unix par la pratique

Avant de lire les arguments de la ligne de commande, nous devons initialiser une variable systme nomme OPTIND, ce qui a lieu la ligne 14. Le rle de cette variable sera dtaill plus bas. La ligne 16 introduit une boucle while. Voici la syntaxe de ce type de boucle :while condition do corps de la boucle... done

Les instructions contenues dans le corps de la boucle sont rptes tant que la condition indique est vraie. An de rendre lcriture un peu plus compacte, il est frquent de remplacer le saut de ligne qui se trouve aprs la condition par un caractre point-virgule, qui, en programmation shell, signie n dinstruction . La boucle est donc gnralement crite ainsi :while condition ; do corps de la boucle done

Une erreur frquente chez les dbutants est de tenter de placer le point-virgule l o il parat visuellement le plus naturel pour un programmeur C ou Pascal : en n de ligne. Sa position correcte est pourtant bien avant le do! Ici, la condition est exprime par une commande interne du shell :getopts ":dfirRvels-:" opt

La commande getopts permet danalyser les arguments qui se trouvent sur la ligne de commande. Nous lui fournissons une chane de caractres qui contient les lettres attribues aux options (comme dans le tableau de la page prcdente), et le nom dune variable quelle devra remplir. Cette fonction renvoie une valeur vraie tant quelle trouve une option qui est contenue dans la liste, et place le caractre dans la variable opt. Nous dtaillerons ultrieurement le fonctionnement de cette routine, et la signication des deux-points prsents dans cette chane. Retenons simplement quarrivs la ligne 17, nous savons que lun des caractres inscrits dans la chane est prsent dans la variable opt. Sur cette ligne 17, nous trouvons une structure de slection case qui va nous permettre de distribuer le contrle du programme en fonction du contenu dune variable. Sa syntaxe est la suivante :case expression in valeur_1 ) action_1 ;; valeur_2 ) action_2 ;; esac

La valeur renvoye par lexpression, ici le contenu de la variable opt, est compare successivement aux valeurs proposes jusqu ce quil en soit trouv une qui lui corresponde, et laction associe est alors excute. Les diffrents cas sont spars par deux

Programmation Shell CHAPITRE 2

19

points-virgules. Pour le dernier cas, toutefois, ce signe de ponctuation est facultatif, mais il est recommand de lemployer quand mme, an dviter des problmes ultrieurs si un nouveau cas doit tre ajout. Le mot-cl esac (case lenvers), que lon trouve la ligne 49, sert marquer la n de cette structure de slection. Nous remarquons au passage que, ligne 17, nous lisons pour la premire fois le contenu dune variable. Cela seffectue en prxant son nom par un caractre $. Ainsi, nous nous rfrons au contenu de la variable opt en crivant $opt. Il faut bien comprendre ds prsent que le nom rel de la variable est bien opt; le $ est un oprateur demandant daccder son contenu. Nous verrons plus avant des formes plus gnrales de cet oprateur. Les valeurs auxquelles lexpression est compare dans les diffrentes branches de la structure case ne sont pas limites de simples valeurs entires, comme peuvent y tre habitus les utilisateurs du langage C, mais peuvent reprsenter des chanes de caractres compltes, incorporant des caractres gnriques comme lastrisque *. Ici, nous nous limiterons employer le caractre | qui reprsente un OU logique, la ligne 21. Ainsi lactionopt_recursive=1

est excute si le caractre contenu dans opt est un r ou un R. Nous observons que les lignes 19 25 servent remplir les variables qui reprsentent les options en fonction des caractres rencontrs par getopts. Un cas intressant se prsente la ligne 26, puisque nous avons rencontr un caractre doption constitu par un tiret. Cela signie que loption commence par --. Dans la chane de caractres que nous avons transmise getopts la ligne 16, nous avons fait suivre le tiret dun deux-points. Cela indique la commande getopts que nous attendons un argument loption -. Il sagit dune astuce pour traiter les options longues comme --help. Lorsque getopts rencontre loption -, il place largument qui la suit (par exemple help) dans la variable OPTARG. Nous pouvons donc reprendre une structure de slection case pour examiner le contenu de cette variable, ce qui est fait de la ligne 26 la ligne 46 o se trouve le esac correspondant. Les options longues, directory, force, interactive, verbose, recursive, empty, list, restore, sont traites comme leurs homologues courtes, dcrites dans le tableau prcdent. Aussi les options help et version commencent par invoquer la vritable commande rm an quelle afche ses propres informations, avant dcrire leurs messages laide de la commande echo. On remarquera que ces deux cas se terminent par une commande return0, ce qui provoque la n de la fonction rm, et renvoie un code de retour nul indiquant que tout sest bien pass. Le motif mis en comparaison sur la ligne 44, un simple astrisque, peut correspondre nimporte quelle chane de caractres selon les critres du shell. Ce motif sert donc absorber toutes les saisies non valides dans les options longues. Nous afchons dans ce cas un message derreur au moyen de la commande :echo "option illgale --$OPTARG"

20

Shells Linux et Unix par la pratique

Nous remarquons quau sein de la chane de caractres encadre par des guillemets, loprateur $ agit toujours, et remplace OPTARG par son contenu, cest--dire le texte de loption longue errone. En ce cas, nous invoquons la commande return avec un argument 1, ce qui signie conventionnellement quune erreur sest produite. la ligne 47, nous revenons la premire structure de distribution case-esac. Nous avions mis la ligne 16 un deux-points en premire position de la chane doptions transmise getopts. Cela permet de congurer le comportement de cette commande lorsquelle rencontre une lettre doption non valide. Dans ce cas, elle met le caractre ? dans la variable indique, opt en loccurrence, stocke la lettre non valide dans la variable OPTARG, et nafche aucun message derreur. Notre dernier cas, sur la ligne 47, sert donc afcher un message derreur, et arrter la fonction avec un code dchec. Aprs clture avec esac et done de la lecture des options, il nous reste traiter les autres arguments qui se trouvent sur la ligne de commande, ceux qui ne sont pas des options, cest--dire les noms de chiers ou de rpertoires quil faut supprimer ou rcuprer. Lorsquun script (ou une fonction) est invoqu, les arguments lui sont transmis dans des variables spciales. Ces variables, accessibles uniquement en lecture, sont reprsentes par le numro de largument sur la ligne de commande. Ainsi, $1 renvoie la valeur du premier argument, $2 celle du deuxime, et ainsi de suite. Nous verrons ultrieurement quil existe aussi des variables spciales, accessibles avec $0, $#, $* et $@, qui aident manipuler ces arguments. La boucle while autour de getopts a parcouru toutes les options qui se trouvent en dbut de ligne de commande, puis elle se termine ds que getopts rencontre un argument qui ne commence pas par un tiret. Avant danalyser un argument, getopts stocke son indice dans la variable OPTIND, que nous avions initialise zro la ligne 14. Si les n premiers arguments de la ligne de commande sont des options valides, en sortie de la boucle while, la variable OPTIND vaut n+1. Il est donc prsent ncessaire de sauter les OPTIND-1 premiers arguments pour passer aux noms de chiers ou de rpertoires. Cest ce qui est ralis sur la ligne 51 :shift $(($OPTIND - 1))

La construction $(()) encadre une expression arithmtique que le shell doit interprter. Ici, il sagit donc simplement du nombre darguments liminer, soit $OPTIND-1. La commande shiftn dcale les arguments en supprimant les n premiers. Nous allons entrer prsent dans le vif du sujet, avec les fonctionnalits vritables du script. Toutefois, nous allons auparavant crer le rpertoire de sauvegarde, sil nexiste pas encore. Cela nous vitera de devoir vrier sa prsence plusieurs reprises dans le reste du programme. Nous voyons donc apparatre sur les lignes 54 56 une nouvelle structure de contrle, le test if-then-else. Sa syntaxe est la suivante :if condition then action else autre action fi

Programmation Shell CHAPITRE 2

21

On regroupe souvent les deux premires lignes en une seule, en sparant les deux commandes par un point-virgule, comme ceci :if condition ; then action else autre action fi

Si la condition est value une valeur vraie, la premire action est excute. Sinon, le contrle passe la seconde partie, aprs le else. Dans notre cas, la condition est reprsente par une expression a priori surprenante :[ ! -d "$sauvegarde_rm" ]

En fait, la construction [] reprsente un test. Il existe dailleurs un synonyme de cette construction qui scrit test. On pourrait donc formuler notre expression comme ceci :test!d"$sauvegarde_rm"

Lemploi des crochets est plus rpandu, peut-tre par souci de concision. On notera quil ne sagit pas simplement de caractres dencadrement comme () ou {}, mais bien dune construction logique complte, chaque caractre tant indpendant. Cela signie que les deux crochets doivent tre entours despaces. Il ne faut pas essayer de les coller leur contenu comme on pourrait avoir tendance le faire : [!d"$sauvegarde_rm"], le shell ne le permet pas. Loption d du test permet de vrier si le nom fourni en argument est bien un rpertoire existant. Le point dexclamation qui se trouve au dbut sert inverser le rsultat du test. Les lignes 54 56 peuvent donc sexprimer ainsi : si le rpertoire $sauvegarde_rm nexiste pas, alorsmkdir "$sauvegarde_rm"

n On pourrait amliorer cette cration de deux manires : Il serait bon de vrier si mkdir a russi la cration. Sil existe dj un chier normal qui a le nom prvu pour le rpertoire de sauvegarde, ou si lutilisateur na pas de droit dcriture sur le rpertoire parent, cette commande peut en effet chouer. Il faudrait alors en tenir compte pour son comportement ultrieur. Pour garder une certaine condentialit aux chiers supprims, il serait bon de protger le rpertoire contre les accs des autres utilisateurs. On pourrait prvoir une commande chmod700"$sauvegarde_rm" aprs la cration. Nous pouvons commencer prsent faire agir le script en fonction des options rclames. Tout dabord, les lignes 59 62 grent loption de vidage de la corbeille :59 60 61 62 if [ $opt_empty -ne 0 ] ; then /bin/rm -rf "$sauvegarde_rm" return 0 fi

22

Shells Linux et Unix par la pratique

Le test [ xxx -ne yyy ] est une comparaison arithmtique entre xxx et yyy. Il renvoie une valeur vraie si les deux lments sont diffrents (not equal). En dautres termes, ces lignes signient : si la variable reprsentant loption empty nest pas nulle, alors effacer le rpertoire de sauvegarde quitter la fonction en indiquant une russite n La deuxime option que nous traitons est la demande dafchage du contenu de la corbeille. Pour ce faire, nous employons les lignes 66 et 67 :( cd "$sauvegarde_rm" ls -lRa * )

Elles correspondent un dplacement vers le rpertoire de sauvegarde, et un afchage rcursif de son contenu et de celui des sous-rpertoires. Nous avons encadr ces deux lignes par des parenthses. On demande ainsi au shell de les excuter dans un sous-shell indpendant, ce qui prsente lavantage de ne pas modier le rpertoire de travail du shell principal. Un nouveau processus est donc cr, et seul le rpertoire de travail de ce processus est modi. Loption traite ensuite est la rcupration de chiers ou de rpertoires effacs. Une boucle stend des lignes 72 75 :while [ -n "$1" ] ; do mv "${sauvegarde_rm}/$1" . shift done

Le test [ -n "$1" ] vrie si la longueur de la chane "$1" est non nulle. Ce test russit donc tant quil reste au moins un argument traiter. Linstruction shift que lon trouve sur la ligne 74 sert liminer largument que lon vient de traiter. Cette boucle permet ainsi de balayer tous les noms de chiers ou de rpertoires un par un. La ligne 73 essaie de rcuprer dans le rpertoire sauvegarde_rm un ventuel chier sauvegard, en le dplaant vers le rpertoire courant. Remarquons quil est tout fait possible, avec cette mme commande, de rcuprer des arborescences compltes, y compris les sous-rpertoires. La portion du programme qui soccupe des suppressions se situe entre les lignes 80 et 102. Elle est construite au sein dune boucle while-do qui balaie les noms des chiers et des rpertoires indiqus sur la ligne de commande. Une premire tape consiste interroger lutilisateur si loption interactive a t rclame, et si loption force ne la pas t. Nous voyons au passage comment deux conditions peuvent tre regroupes par un ET logique au sein dun test. Nous reviendrons sur ce mcanisme ultrieurement. Aprs dclaration dune variable locale, et afchage dun message dinterrogation (avec loption -n de echo pour viter daller la ligne), le script invoque la commande shell read. Cette dernire lit une ligne et la place dans la variable indique en argument.

Programmation Shell CHAPITRE 2

23

Nous comparons alors cette rponse avec quatre chanes possibles : y, Y, o, et O. Loprateur de comparaison des chanes est =, et son inverse est !=. Si la rponse ne correspond aucune de ces possibilits, nous invoquons dabord shift, pour dcaler les arguments, puis la commande continue qui nous permet de revenir au dbut de la boucle while. Les arguments pour lesquels lutilisateur na pas rpondu par lafrmative sont ainsi oublis . La deuxime vrication concerne les rpertoires. Ceux-ci, en effet, ne peuvent tre effacs quavec loption recursive. Si le test de la ligne 92 choue, largument est ignor et on passe au suivant. Si on a rclam un comportement volubile du programme (option -v ou --verbose), on afche le nom du chier ou du rpertoire trait avant de poursuivre. Puis, les lignes 100 et 101 dplacent effectivement le chier, et passent largument suivant. La fonction qui remplace la commande rm est donc prsent crite. Lorsque le script est excut laide de linstruction source ou de . , il place cette fonction dans la mmoire du shell ; elle est prte tre invoque la place de rm. Il demeure toutefois une dernire ligne apparemment mystrieuse :trap "/bin/rm -rf $sauvegarde_rm" EXIT

Cette ligne est excute directement par le shell lorsque nous appelons notre script. La commande trap permet dassurer une gestion minimale des signaux. Voici sa syntaxe gnrale :trap commande signal

Lorsque le shell recevra le signal indiqu, il droutera son excution pour raliser immdiatement la commande passe en argument. Les signaux permettent une communication entre processus, et surtout une prise en compte asynchrone des vnements quun logiciel peut tre amen rencontrer (interruption dune ligne de communication, n dune temporisation, dpassement dune limite doccupation du disque, etc.). Nous reviendrons plus en dtail sur la gestion des signaux ultrieurement. Ici, la commande trap nous sert intercepter un pseudo-signal simul par le shell. En effet, avant que le shell ne se termine, il simule lmission dun signal nomm EXIT. La commande passe en argument est donc excute juste avant de refermer une session de travail. Elle sert effacer le rpertoire de sauvegarde. Cette ligne est bien entendu optionnelle, mais je conseille de la conserver, car elle vite lutilisateur de devoir vider explicitement sa corbeille (manuellement ou dune manire programme laide de la crontab).

PerformancesLutilitaire rm_secure na pas pour objet de fournir une rcupration des chiers sur du long terme. Ce rle est dvolu aux mcanismes de sauvegarde priodique du systme. En fait, rm_secure est conu comme une sorte de commande Contrle-Z ou dition/Annuler qui permet de corriger immdiatement une erreur de frappe ayant entran la destruction

24

Shells Linux et Unix par la pratique

involontaire dun chier. En tenant compte de ses spcicits, chacun est toujours libre de modier le script sa convenance pour ladapter un cas particulier. Il faut aussi tre conscient que, dans un environnement graphique X Window, o plusieurs fentres xterm sont utilises simultanment, ds que lon ferme lune dentre elles, la commande deffacement est invoque, dtruisant le rpertoire de sauvegarde commun toutes les fentres. Si ce point pose un problme, il est malgr tout possible de crer un rpertoire de sauvegarde pour chaque instance indpendante du shell. On obtient cela en ajoutant au nom du rpertoire un sufxe qui reprsente le PID du shell, en remplaant la premire ligne du script par :sauvegarde_rm=~/.rm_saved_$$/

Un tel script a pour vocation de rester le plus discret possible vis--vis de lutilisateur. Idalement, on ne devrait se souvenir de sa prsence que le jour o un chier vient dtre effac maladroitement. Il faut donc viter de ralentir le fonctionnement de la commande rm originale. cet effet, nous avons fait le choix de dplacer les chiers avec mv plutt que de les copier avec cp, ou des les archiver avec tar. Lorsque le chier quil faut supprimer se trouve sur le mme systme de chiers que le rpertoire de sauvegarde, la commande mv agit instantanment, car elle ne doit modier que le nom du chier dans larborescence, et pas son contenu. Il sagit du cas le plus courant pour les utilisateurs normaux, dont les rpertoires personnels et tous les descendants se trouvent gnralement sur la mme partition. Pour root, en revanche, la situation est autre, car ce dernier doit souvent intervenir sur des rpertoires qui se trouvent sur des partitions diffrentes. La commande mv ne peut plus simplement dplacer le chier, mais est oblige de le copier, puis de supprimer loriginal. Dans ce cas, notre script induit un ralentissement sensible, notamment lorsquon agit sur des hirarchies compltes (par exemple, en supprimant toute larborescence des sources dun programme) ou sur des chiers volumineux (core, par exemple). On peut choisir de dsactiver lemploi de rm_secure pour root, en partant du principe que toute action entreprise sous ce compte est potentiellement dangereuse, et ncessite une attention accrue tout moment. Idalement, la connexion root sur un systme Unix ou Linux qui compte peu dutilisateurs devrait tre rserve linstallation ou la suppression de paquetages logiciels, lajout dutilisateur et ldition de chiers de conguration (connexion distante, adressage rseau). Dans tous ces cas, on nintervient que sur des chiers dont une copie existe ailleurs (CD, bande de sauvegarde, Internet). Thoriquement, root ne devrait jamais se dplacer et encore moins toucher aux chiers dans les rpertoires personnels des utilisateurs o lon trouve des donnes nexistant quen un seul exemplaire (chiers source, textes, e-mail). Thoriquement

Exemple dexcutionVoici, en conclusion de ce survol dun script pour shell, un exemple dutilisation. Nous supposons que les chiers dinitialisation (~/.profile ou ~/.bashrc), excuts lors du dmarrage des sessions interactives du shell, contiennent une ligne qui permette dinvoquer le script, la manire de .~/bin/rm_secure.sh. Nous considrons donc que la

Programmation Shell CHAPITRE 2

25

fonction rm dnie prcdemment est prsente dans lenvironnement, et a prsance sur le chier excutable /bin/rm.$ ls rm_secure.sh rm_secure.sh.bak

Je souhaite ne supprimer que le chier de sauvegarde, et jappelle donc rm*.bak pour viter de saisir son nom en entier. Hlas, jintroduis par erreur un caractre espace aprs lastrisque.$ rm * .bak mv:.bak.: Aucun fichier ou rpertoire de ce type $ ls $

Ae ! Il ne me reste plus qu compter sur laide de notre script. Commenons par nous remmorer ses options :$ rm --help Usage: /bin/rm [OPTION]... FICHIER... Enlever (unlink) les FICHIER(s). enlever le rpertoire, mme si non vide (usager root seulement) -f, --force ignorer les fichiers inexistants, ne pas demander de confirmation -i, --interactive demander confirmation avant destruction -r, -R, --recursive enlever les rpertoires rcursivement -v, --verbose en mode bavard expliquer ce qui est fait --help afficher l'aide-mmoire --version afficher le nom et la version du logiciel Rapporter toutes anomalies . rm_secure: -e --empty vider la corbeille -l --list voir les fichiers sauvs -s, --restore rcuprer des fichiers $ rm -l -rwxr-xr-x cpb/cpb 2266 2007-09-01 19:39:14 rm_secure.sh -rwxr-xr-x cpb/cpb 2266 2007-09-01 19:39:14 rm_secure.sh.bak $ rm --restore rm_secure.sh $ ls rm_secure.sh -d, --directory

26

Shells Linux et Unix par la pratique

Ouf ! Le chier est rcupr. Vrions maintenant que le rpertoire de sauvegarde est bien vid automatiquement lors de la dconnexion :$ rm --list -rwxr-xr-x cpb/cpb $ exit 2266 2007-09-01 19:39:14 rm_secure.sh.bak

Essayons de voir sil reste des chiers aprs une nouvelle connexion :$ rm --list ls: *: Aucun fichier ou rpertoire de ce type $

Ce dernier message nest peut-tre pas trs heureux. Nous laisserons au lecteur le soin dencadrer lappel ls de la ligne 67 par un test if-then-fi qui afche un message plus appropri si la commande ls signale une erreur (ne pas oublier de rediriger la sortie derreur standard de cette dernire commande vers /dev/null pour la dissimuler).

ConclusionAvec ce chapitre dintroduction la programmation shell, nous avons pu observer la structure des scripts, que nous pourrons tudier plus en dtail par la suite. On peut remarquer la concision de ce langage, qui permet de raliser une tche dj respectable en une centaine de lignes de programmation. Et ce, en raison du niveau dabstraction lev des commandes employes. Par exemple, la suppression rcursive dun rpertoire, comme nous lavons vu dans la dernire ligne du script, demanderait au moins une vingtaine de lignes de programmation en C. Les chapitres venir vont nous permettre dtudier la programmation shell dune manire plus formelle, et plus complte.

Exercices2.1 Appel dun script par source (facile)Crez un script qui initialise une nouvelle variable avec une valeur arbitraire, puis afche cette variable. Lancez le script (aprs lavoir rendu excutable avec chmod) comme nous lavons fait dans le chapitre 1. Une fois lexcution termine, essayez dafcher le contenu de la variable :

initialise_et_affiche.sh #! /bin/sh

Programmation Shell CHAPITRE 2

27

ma_variable=2007 echo $ma_variable $ chmod 755 initialise_et_affiche.sh $ ./initialise_et_affiche.sh 2007 $ echo $ma_variableRsultat ? Essayez prsent dexcuter le script avec linvocation suivante :

$ . initialise_et_affiche.shEt essayez ensuite de consulter le contenu de la variable. N. B. : vous pouvez remplacer le . de linvocation par le mot-cl source si vous travaillez avec bash.

2.2 Utilisation de rm_secure.sh (plutt facile)ditez le chier de personnalisation de votre shell de connexion (.bashrc, .profile...) et insrez-y la ligne :

. ~/bin/rm_secure.shPrenez soin de placer le script rm_secure.sh dans le sous-rpertoire bin/ de votre rpertoire personnel. Reconnectez-vous, et essayez prsent dappeler :

$ rm -vpour vrier si le script est bien appel la place de la commande rm habituelle. Effectuez quelques essais deffacement et de rcupration de chiers.

2.3 Adaptation de rm_secure.sh (plutt difcile)En examinant le contenu du script rm_secure.sh, essayez dy apporter quelques modications (par exemple modiez le rpertoire de sauvegarde) et amliorations (par exemple la condentialit sera augmente si le script retire aux chiers sauvegards tous les droits daccs, hormis leur propritaire).

3valuation dexpressionsUne part importante de la programmation de scripts repose sur une bonne comprhension des mcanismes qui permettent au shell dvaluer correctement les expressions reues. Nous allons donc commencer par tudier lutilisation des variables, avant dobserver en dtail les valuations dexpressions. Une fois que cela aura t effectu, ltude des structures de contrle et des fonctions internes du shell sera plus facile, et nous serons mme de raliser de vritables scripts.

VariablesLa programmation sous shell ncessite naturellement des variables pour stocker des informations temporaires, accder des paramtres, etc. Par dfaut, les variables utilises dans les scripts shell ne sont pas types. Le contenu dune variable est considr comme une chane de caractres, sauf si on indique explicitement quelle doit tre traite comme une variable entire qui peut tre utilise dans des calculs arithmtiques. De plus, le shell ne permet pas de manipuler directement de donnes en virgule ottante (sauf les versions rcentes de Ksh, mais sans garantie de portabilit). Nous verrons plus avant comment il convient demployer lutilitaire bc au sein de scripts shell pour raliser des oprations sur des nombres rels. la diffrence des langages compils habituels, une variable na pas tre dclare explicitement. Ds quon lui affecte une valeur, elle commence exister. Cette affectation prend la forme variable=valeur sans espaces autour du signe gal. Le message

30

Shells Linux et Unix par la pratique

derreur i: command not found est peut-tre le plus clbre parmi les utilisateurs du shell :$ i = 1 bash: i: command not found $

cause des espaces autour du signe gal, Bash a cru que lon essayait dinvoquer la commande i en lui transmettant les arguments = et 1. La bonne syntaxe est la suivante :$ i=1 $

Pour accder au contenu dune variable, il suft de prxer son nom avec le caractre $. Il ne faut pas confondre ce prxe des variables avec le symbole dinvite du shell, qui est gnralement le mme caractre $. La commande echo afche simplement le contenu de sa ligne de commande :$ echo $i 1 $

Le nom attribu une variable peut contenir des lettres, des chiffres, ou le caractre soulign _. Il ne doit toutefois pas commencer par un chiffre. Voyons quelques exemples :$ variable=12 $ echo $variable 12 $

Il faut bien comprendre que le shell a remplac la chane $variable par sa valeur, 12, avant dappeler la commande echo. Cette dernire a donc t invoque par la ligne de commande echo12.$ variable=abc def bash: def: command not found $

valuation dexpressions CHAPITRE 3

31

Ici, le shell na pas pu interprter correctement cette ligne, car il a cru quelle se composait dune affectation variable=abc, suivie dune commande nomme def (syntaxe rarement utilise mais autorise). Il faut lui indiquer que les mots droite du signe gal forment une seule chane de caractres. On emploie pour cela les guillemets droits :$ variable="abc def" $ echo $variable abc def $

Nous pouvons vrier quune variable qui na jamais t affecte est considre comme une chane vide :$ echo $inexistante $

Une variable laquelle on affecte une chane vide existe quand mme. La diffrence entre une variable inexistante et une variable vide peut tre mise en vidence laide de certaines options des constructions de test, ou par lintermdiaire dune conguration particulire du shell qui dclenchera une erreur si on essaie de lire le contenu dune variable inexistante. Cette conguration sobtient au moyen de la commande interne set (que nous dtaillerons dans le chapitre 5) et de son option -u.$ set -u $ echo $inexistante bash: inexistante: unbound variable $ vide= $ echo $vide $

Prcisions sur loprateur $On consulte le contenu dune variable laide de loprateur $. Toutefois, la forme $variable, mme si elle est la plus courante, est loin dtre la seule, et loprateur $ propose des fonctionnalits dune richesse surprenante.

32

Shells Linux et Unix par la pratique

Dlimitation du nom de variable

Tout dabord, la construction ${variable} est une gnralisation de $variable, qui permet de dlimiter prcisment le nom de la variable, dans le cas o on souhaiterait le coller un autre lment. Par exemple, supposons que nous souhaitions classer les chiers source dune bibliothque de fonctions, en leur ajoutant un prxe qui corresponde au projet auquel ils appartiennent. Nous pourrions obtenir une squence du type :$ PREFIXE=projet1 $ FICHIER=source1.c $ NOUVEAU_FICHIER=$PREFIXE_$FICHIER

On espre obtenir projet1_source1.c dans la variable NOUVEAU_FICHIER, mais malheureusement ce nest pas le cas :$ echo $NOUVEAU_FICHIER source1.c $

Le fait davoir accol directement $PREFIXE, le caractre soulign et $FICHIER ne fonctionne pas comme nous lattendions : le shell a bien remarqu quil y a deux oprateurs $ agissant chacun sur un nom de variable, mais seul le second a t correctement remplac. En effet, le caractre soulign que nous avons ajout comme sparateur entre le prxe et le nom du chier a t considr comme appartenant au nom de la premire variable. Ainsi le shell a-t-il recherch une variable nomme PREFIXE_ et nen a videmment pas trouv. La raison en est que le caractre soulign nest pas un caractre sparateur pour le shell, et quon peut le rencontrer dans les noms de variables. Si nous avions utilis un caractre interdit dans ces noms, nous naurions pas eu le mme problme, car le premier nom de variable aurait t clairement dlimit :$ echo $PREFIXE.$FICHIER projet1.source1.c $ echo $PREFIXE@$FICHIER [email protected] $ echo $PREFIXE-$FICHIER projet1-source1.c $

valuation dexpressions CHAPITRE 3

33

On pourrait mme utiliser les guillemets droits pour encadrer le caractre soulign an de le sparer du nom de la variable. Ce mcanisme sera dtaill plus avant, lorsque nous tudierons les mthodes de protection des caractres spciaux.$ echo $PREFIXE"_"$FICHIER projet1_source1.c $

Quoi quil en soit, il arrive que lon doive ajouter des caractres la n dun nom de variable, et loprateur ${} est alors utilis la place du simple $ pour marquer les limites. Ainsi, on peut utiliser :$ echo ${PREFIXE}_$FICHIER projet1_source1.c $

ou des constructions comme :$ singulier=mot $ pluriel=${singulier}s $ echo $pluriel mots $

Extraction de sous-chanes et recherche de motifs

Les shells rcents offrent une possibilit dextraction automatique de sous-chanes de caractres au sein dune variable. La version la plus simple sappuie sur loption : de loprateur ${}. Ainsi lexpression ${variable:debut:longueur} est-elle automatiquement remplace par la sous-chane qui commence lemplacement indiqu en seconde position, et qui contient le nombre de caractres indiqu en dernire position. La numrotation des caractres commence zro. Si la longueur nest pas mentionne, on extrait la sous-chane qui stend jusqu la n de la variable. En voici quelques exemples :$ variable=ABCDEFGHIJKLMNOPQRSTUVWXYZ $ echo ${variable:5:2} FG $ echo ${variable:20} UVWXYZ $

34

Shells Linux et Unix par la pratique

Cette extraction nest pas dcrite dans les spcications Single Unix version 3, et on lui accordera donc une conance limite en ce qui concerne la portabilit. Ce mcanisme fonctionne sans surprise, mais nest pas aussi utile, dans le cadre de la programmation shell, que lon pourrait le croire au premier abord. Dans nos scripts, nous manipulons en effet souvent des noms de chiers ou des adresses rseau, et une autre possibilit dextraction de sous-chane se rvle en gnral plus adapte : elle repose sur lemploi de motifs qui sont construits de la mme manire que lors des recherches de noms de chiers en ligne de commande. Ces motifs peuvent contenir des caractres gnriques particuliers : Le caractre * correspond nimporte quelle chane de caractres (ventuellement vide). Le caractre ? correspond nimporte quel caractre. Le caractre \ permet de dsactiver linterprtation particulire du caractre suivant. Ainsi, la squence \* correspond lastrisque, \? au point dinterrogation et \\ au caractre backslash (barre oblique inverse). Les crochets [ et ] encadrant une liste de caractres reprsentent nimporte quel caractre contenu dans cette liste. La liste peut contenir un intervalle indiqu par un tiret comme A-Z. Si lon veut inclure les caractres - ou ] dans la liste, il faut les placer en premire ou en dernire position. Les caractres ^ ou ! en tte de liste indiquent que la correspondance se fait avec nimporte quel caractre qui nappartient pas lensemble. Lextraction de motifs peut se faire en dbut, en n, ou au sein dune variable. Il sagit notamment dune technique trs prcieuse pour manipuler les prxes ou les sufxes des noms de chiers. Lexpression ${variable#motif} est remplace par la valeur de la variable, de laquelle on te la chane initiale la plus courte qui corresponde au motif :$ variable=AZERTYUIOPAZERTYUIOP $ echo ${variable#AZE} RTYUIOPAZERTYUIOP

La portion initiale AZE a t supprime.$ echo ${variable#*T} YUIOPAZERTYUIOP

Tout a t supprim jusquau premier T.$ echo ${variable#*[MNOP]} PAZERTYUIOP

valuation dexpressions CHAPITRE 3

35

limination du prxe jusqu la premire lettre contenue dans lintervalle.$ echo ${variable#*} AZERTYUIOPAZERTYUIOP

Suppression de la plus petite chane quelconque, en loccurrence la chane vide, et il ny a donc pas dlimination de prxe.Tableau 3-1 : Actions de loprateur ${#...}variable ${variable#AZE} ${variable#*T} ${variable#*[MNOP]} ${variable#*} AZERTYUIOPAZERTYUIOP RTYUIOPAZERTYUIOP YUIOPAZERTYUIOP PAZERTYUIOP AZERTYUIOPAZERTYUIOP

Lexpression ${variable##motif} sert liminer le plus long prxe correspondant au motif transmis. Ainsi, les exemples prcdents nous donnent :$ echo ${variable##AZE} RTYUIOPAZERTYUIOP

La chane AZE ne peut correspondre quaux trois premires lettres ; pas de changement par rapport loprateur prcdent.$ echo ${variable##*T} YUIOP

Cette fois-ci, le motif absorbe le plus long prxe qui se termine par un T.$ echo ${variable##*[MNOP]}

Le plus long prxe se terminant par M, N, O ou P correspond la chane elle-mme, puisquelle se nit par P. Lexpression renvoie donc une chane vide.$ echo ${variable##*}

36

Shells Linux et Unix par la pratique

De mme, la suppression de la plus longue chane initiale, compose de caractres quelconques, renvoie une chane vide.Tableau 3-2 : Actions de loprateur ${##...}variable ${variable##AZE} ${variable##*T} ${variable##*[MNOP]} ${variable##*} AZERTYUIOPAZERTYUIOP RTYUIOPAZERTYUIOP YUIOP

Symtriquement, les expressions ${variable%motif} et ${variable%%motif} correspondent au contenu de la variable indique, qui est dbarrass, respectivement, du plus court et du plus long sufxe correspondant au motif transmis. En voici quelques exemples :$ variable=AZERTYUIOPAZERTYUIOP $ echo ${variable%IOP*} AZERTYUIOPAZERTYU $ echo ${variable%%IOP*} AZERTYU $ echo ${variable%[X-Z]*} AZERTYUIOPAZERT $ echo ${variable%%[X-Z]*} A $ echo ${variable%*} AZERTYUIOPAZERTYUIOP $ echo ${variable%%*} $Tableau 3-3 : Actions des oprateurs ${%...} et ${%%...}Variable ${variable%IOP*} ${variable%%IOP*} ${variable%[X-Z]*} ${variable%%[X-Z]*} ${variable%*} ${variable%%*} AZERTYUIOPAZERTYUIOP AZERTYUIOPAZERTYU AZERTYU AZERTYUIOPAZERT A AZERTYUIOPAZERTYUIOP

valuation dexpressions CHAPITRE 3

37

Un oprateur est apparu dans Bash 2, qui permet de remplacer une portion de chane grce aux expressions : ${variable/motif/remplacement} qui permet de remplacer la premire occurrence du motif par la