diff --git a/unix/shell/fonction.tml b/unix/shell/fonction.tml new file mode 100644 index 0000000..df12bd4 --- /dev/null +++ b/unix/shell/fonction.tml @@ -0,0 +1,412 @@ + + + +
++Vous savez qu'un script shell n'est rien d'autre qu'une série de +commandes (si vous ne le savez pas, lisez la page d'initiation à la programmation en shell). Mais +parfois cela pose des problèmes, car lorsqu'un script devient un peu +long et surtout lorsqu'il est obligé de se répéter, les risques de +bogues (dysfonctionnements) croissent. +
+ ++L'usage des fonctions permet de : +
+ +
+Utilisateur de TeX, vous voulez effacer régulièrement tous les fichiers
+.aux
et .log
qui polluent vos répertoires.
+Pour ceux qui ne connaissent pas TeX, sachez que ce sont des fichiers
+construits automatiquement, et que l'on peut recréer facilement à partir
+du fichier .tex
: les supprimer permet donc de gagner
+de l'espace disque sans dommages.
+
+Votre script ressemble donc à ceci : +
+ ++#!/bin/sh + +# fichier "texcleaner" : efface les fichiers aux et log + +# Je prends chaque fichier .aux du répertoire courant +for fichier in *.aux + do + # J'affiche son nom et demande confirmation pour l'effacer + echo "$fichier" + echo "Voulez-vous vraiment l'effacer ? (o/n)" + + # Je lis la réponse de l'utilisateur + read reponse + + # Et s'il dit oui, j'efface + if [[ $reponse == "o" ]] + then rm -f $fichier + fi +done + +# Je prends chaque fichier .log du répertoire courant +for fichier in *.log + do + # J'affiche son nom et demande confirmation pour l'effacer + echo "$fichier" + echo "Voulez-vous vraiment l'effacer ? (o/n)" + + # Je lis la réponse de l'utilisateur + read reponse + + # Et s'il dit oui, j'efface + if [[ $reponse == "o" ]] + then rm -f $fichier + fi +done ++ +
+Vous venez de terminer ce programme, et vous êtes content, car il +fonctionne comme vous le voulez. +
+ + ++Ce programme présente certains aspects déplaisants : +
+ ++Il faudrait, pour pallier ces inconvénients, trouver un moyen de +centraliser les informations destinées à être répétées, afin que +l'on puisse s'y référer à chaque endroit où cela est +nécessaire. C'est pour cela que les fonctions existent. +
+ + + ++L'utilisation des fonctions se fait en deux moments : +
+ ++Dans le monde naturel, on peut comparer cela à l'horloge parlante : +celle-ci commence par dire « au quatrième top, il sera neuf heures +cinquante-deux », puis « top... top... top... top. » +
+ ++On pourrait dire que dans un premier temps, l'horloge parlante +définit une fonction, en assignant un signal (le quatrième top) +à ce qu'il signale (il est neuf heures cinquante-deux) ; une fois +cela clairement défini, l'horloge égrène les quatre +« top », et le quatrième renvoie à l'énoncé « il est +neuf heures cinquante-deux ». +
+ ++En langage naturel, définir une fonction équivaut à dire : +quand je dirai le nom de la fonction, vous l'exécuterez. C'est +un acte de langage, comme quand un arbitre dit aux athlètes : +« Go ! » ; car tous les athlètes savent que le +signifiant « Go ! » (ou le coup de pistolet tiré en +l'air) signifie qu'ils doivent partir (la fonction a été définie dans +le règlement officiel de leur sport). +
+ + ++Définir une fonction est extrêmement simple : +
+ ++nom () { +instruction1 +instruction2 +... +} ++ +
+On commence par trouver un nom à la fonction. Vous +pouvez choisir ce nom à votre guise, par exemple liste_des_fichiers, +effacer_fichier, etc. +
+ ++Il est toutefois fortement recommandé : +
+ +ls
, mutt
,
+etc. Cela pourrait en effet poser de graves problèmes, car les fonctions
+définies dans un programme sont prioritaires sur les commandes integrées
+du shell (cd
, alias
, etc.) et les commandes
+externes (mutt
, mozilla
, etc.). Le
+comportement devient difficilement prévisible, et surtout, le script
+sera difficile à débuguer... +Une fois que vous avez donné un nom à la fonction, notez des +parenthèses ouvrante et fermante : ce sont elles +qui indiquent à l'interpréteur du script qu'il s'agit d'une définition +de fonction. +
+ ++Ensuite, entre accolades, notez la série des +instructions qu'il faudra exécuter à chaque appel de la +fonction. +
+ + ++Comme l'interpréteur de scripts shell lit des scripts ligne à ligne, +il faut que la fonction soit définie avant d'être +appelée. Sinon, vous recevez un message de type : +« Command not found » (commande introuvable). Par convention, +il est préférable de placer toutes les définitions de +fonction vers le début du programme, avant toutes les +instructions. +
+ + ++Notre programme sera donc considérablement allégé : +
+ ++#!/bin/sh + +# fichier "texcleaner" : efface les fichiers aux et log + +# Je définis ma fonction effacer_fichier + +effacer_fichier () { + # J'affiche son nom et demande confirmation pour l'effacer + echo "$1" + echo "Voulez-vous vraiment l'effacer ? (o/n)" + + # Je lis la réponse de l'utilisateur + read reponse + + # Et s'il dit oui, j'efface + if [[ $reponse == "o" ]] + then rm -f $1 + fi +} + +# Je prends chaque fichier .aux du répertoire courant +for fichier in *.aux + do + # J'appelle la fonction effacer_fichier pour chaque fichier + effacer_fichier $fichier +done + +# Je prends chaque fichier .log du répertoire courant +for fichier in *.log + do + # J'appelle la fonction effacer_fichier pour chaque fichier + effacer_fichier $fichier +done ++ +
+On économise une dizaine de lignes, on gagne en lisibilité, et les +risques de bogues diminuent considérablement car s'il y a des +corrections à apporter, c'est à un seul endroit du script, et non d'une +façon disséminée sur l'ensemble du programme. +
+ +
+Un détail de la fonction effacer_fichier
peut vous
+étonner : nous utilisons l'argument $1
. Comme vous le
+savez sans doute (sinon, lisez la page sur les commandes
+shell et leurs arguments), $1
désigne le premier
+argument passé à une commande ; or les fonctions peuvent
+recevoir des arguments, exactement de la même façon que les
+commandes. C'est même tout à fait normal, car les fonctions sont
+en fait des commandes comme les autres, à ceci près qu'elles ne sont
+valables qu'à l'échelle d'un script, et non à celle d'un
+système tout entier.
+
+Sachez enfin que des fonctions peuvent appeler d'autres +fonctions, ce qui donne une extrême souplesse à leur +utilisation. +
+ ++En voici un bref exemple : +
+ ++#!/bin/sh + +# Je définis une première fonction + +ecrire_sur_une_ligne () { + echo -n $* +} + +# Je définis une deuxième fonction qui appelle la première + +saluer_utilisateur () { + ecrire_sur_une_ligne "Bonjour " + echo $USER +} + + +# J'appelle la deuxième fonction +saluer_utilisateur + ++ + +
+De là, passons à un conseil de programmation : abusez des +fonctions ! N'hésitez pas à créer des fonctions pour tout +et n'importe quoi. Vous en tirerez : +
+ ++Un programme sans fonction n'est lisible que s'il est très +petit : une vingtaine de lignes tout au plus. Dès qu'un +programme dépasse cette taille, il cesse d'être intelligible d'un seul +coup d'œil pour un humain. +
+ ++Supposons qu'un programme soit amené à répéter n fois un +même fragment de code comportant p lignes ; en +utilisant des fonctions on économise +(n - 1) x p lignes (toutes +les occurrences de la répétition, moins la définition de la fonction). +
+ ++Ce gain de lignes est indissociable d'un gain de lisibilité, car les +répétitions fatiguent inutilement le cerveau humain. +
+ + ++En recopiant « à la main » des fragments identiques de codes, +vous risquez toujours la faute de frappe. Or, la moindre coquille peut +avoir des conséquences, au mieux, imprévisibles ; au pire, +catastrophiques. +
+ ++En isolant les séries d'instructions dans des définitions de fonctions, +vous concentrez en un seul endroit la situation possible d'un bogue +donné. Vous pouvez circonscrire le bogue. +
+ ++En utilisant des fonctions, vous donnez à vos programmes une grande +souplesse. Si vous voulez apporter une modification d'ensemble à un +programme, vous n'avez plus à corriger autant de morceaux du script +qu'il y a d'occurrences du même fragment : vous apportez vos +modifications de manière centralisée. +
+ ++Pour toutes ces raisons, n'hésitez surtout pas à créer des fonctions et +à les emboîter entre elles. La programmation vous paraîtra de plus en +plus facile, à mesure que vous réaliserez des tâches de plus en plus +complexes. +
+ + + + + +