26
100 scripts shell UNIX Dave Taylor Groupe Eyrolles, 2004 pour l’édition française, ISBN : 2-212-11483-4.

Titre 100scripts 30/07/04 10:24 Page 1 100€¦ ·  · 2004-09-02Vous ne trouverez rien de semblable en ligne de commande Unix, ... Pour aller plus loin ... la fonction s'appelle

Embed Size (px)

Citation preview

100scripts

shell UNIXD a v e T a y l o r

Titre_100scripts 30/07/04 10:24 Page 1

Groupe Eyrolles, 2004 pour l’édition française,

ISBN : 2-212-11483-4.

3Créer des utilitaires

Les scripts shell sont essentiellement destinés à stocker sous forme de fichiers reproductiblesdes lignes de commande complexes. Vous pouvez ensuite aisément adapter ces scripts à descontextes spécifiques. C’est pourquoi il nous a fallu deux chapitres complets pour étudier lanotion de commande utilisateur. À ce stade, vous vous demandez probablement pourquoi jen’ai pas tout simplement enveloppé dans un seul script toutes les commandes disponibles surmes systèmes Linux, Solaris et Mac OS X, ou tout au moins pourquoi je n’ai pas adapté etconfiguré leur fonctionnement.

En raison de sa puissance et de sa souplesse, Unix est le seul système d’exploitation majeurqui permette de modifier définitivement en quelques frappes les options par défaut d’unecommande. Vous pouvez également émuler le comportement de votre utilitaire préféré depuisune autre version du système au moyen d’une dizaine de lignes maximum. Je viens derésumer en quelques mots l’intérêt d’Unix, les raisons pour lesquelles vous apprécierez sonutilisation et les motivations qui m’ont incitées à écrire ce livre.

N°23 – Utilitaire de pense-bêteDepuis des années, les utilisateurs de Windows et de Macintosh ont recours à des outils pense-bête simples, qui affichent des messages courts à l’écran. On ne saurait rêver d’un meilleuremplacement pour consigner numéros de téléphone, adresses ou toute information à ne pasoublier. Vous ne trouverez rien de semblable en ligne de commande Unix, mais cela ne doitpas vous arrêter car les deux scripts qui suivent viennent à votre rescousse.

Le premier script, remember (souviens-toi), permet de stocker aisément des bribes d’informa-tions dans un fichier. Appelé sans arguments, il lit l’entrée standard jusqu’à la fin du fichier.

100 scripts shell Unix72

Copyright ©

2004 Groupe E

yrolles

En revanche, si vous passez des arguments, il se contente de les stocker dans son fichier dedonnées.

Son alter ego est remindme (rappelle-moi), script d’accompagnement qui affiche le contenu dufichier mémoire rememberfile lorsqu’il est appelé sans arguments. Dans le cas contraire, ilextrait les lignes correspondant au motif reçu.

Le code

Voici le deuxième script, remindme :

#!/bin/sh # remember - Un petit pense-bête en ligne de commande. rememberfile="$HOME/.remember" if [ $# -eq 0 ] ; then echo "Tapez votre note, finissez avec ^D: " cat - >> $rememberfileelse echo "$@" >> $rememberfile fi exit 0

#!/bin/sh # remindme - Recherche les lignes correspondant à un motif dans le# fichier de notes, ou affiche ce fichier en entier en l'absence# d'argument de ligne de commande. rememberfile="$HOME/.remember" if [ $# -eq 0 ] ; then more $rememberfile else grep -i "$@" $rememberfile | ${PAGER:-more} fi exit 0

Créer des utilitairesCHAPITRE 3

73

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Pour mettre en œuvre l’utilitaire remindme, commencez par consigner des notes, des numérosde téléphone, etc., dans le fichier rememberfile via le script remember. Vous consulterezensuite cette base de données informelle à l’aide de remindme en spécifiant un motif derecherche précis ou flou selon vos besoins.

Les résultats

Si je souhaite me remémorer cette note quelques mois plus tard :

Si j’ai besoin de consigner d’autres données :

Pour aller plus loinBien qu’ils ne soient en aucun cas un tour de force en matière de programmation shell, cesscripts illustrent les possibilités incroyables d’extension d’une ligne de commande Unix. Dèsqu’une idée vous vient à l’esprit, il y a fort à parier qu’il existe une manière simple et directede l’implémenter.

Vous pouvez améliorer ces scripts de diverses façons, par exemple en intégrant le conceptd’enregistrements. Ceux-ci sont susceptibles de se voir attribuer une estampille temporelle etde comporter plusieurs lignes permettant les recherches par expression régulière. Il estpossible de stocker des numéros de téléphone correspondant à des groupes de personnes, puisde retrouver ces groupes en entrant le nom d’un seul de leurs membres. Si la programmationde scripts shell vous passionne, vous pouvez également prévoir d’éditer et d’effacer des enre-gistrements. Dans tous les cas, il est facile d’éditer ~/ remember manuellement.

N°24 – Une calculatrice interactivePour compléter le script n°9, destiné à appeler bc en ligne de commande pour les opérationsutilisant les virgules flottantes, je me devais d’écrire un script enveloppant d’implémentation

$ rememberTapez votre note, finissez avec ^D: Le réseau de la communauté de Boulder: http://bcn.boulder.co.us/^D

$ remindme boulderLe réseau de la communauté de Boulder: http://bcn.boulder.co.us/

$ remindme 800Southwest Airlines: 800-IFLYSWA

100 scripts shell Unix74

Copyright ©

2004 Groupe E

yrolles

d’une calculatrice interactive en ligne de commande. Cet utilitaire est remarquable par saconcision, malgré la présence d’une aide en ligne.

Le code

#! /bin/sh # calc - Une calculatrice en ligne de commande qui sert d'interface à bc. scale=2 show_help() { cat << EOF Outre les fonctions mathématiques classiques, calc connaît aussi: a % b reste de la division entière a/b a ^ b exponentielle: a élevée à la puissance b s(x) sinus de x, x étant exprimé en radians c(x) cosinus de x, x étant exprimé en radians a(x) arctangente de x, renvoie des radians l(x) logarithme naturel de x e(x) exponentielle de x j(n,x) fonction de Bessel d'ordre n de x scale N affiche N chiffres après la virgule (par défaut: 2)EOF} if [ $# -gt 0 ] ; then exec scriptbc "$@" fi echo "Calc - une calculatrice simple. Tapez «help» pour avoir l'aide, «quit» pour quitter." echo -n "calc> " while read command argsdo case $command in quit|exit) exit 0 ;; help|\?) show_help ;;

Créer des utilitairesCHAPITRE 3

75

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Dans le détailUn cas d’école ! La partie la plus intéressante du code est sans doute l’instruction while read,qui met en place une boucle infinie affichant l’invite calc> jusqu’à ce que l’utilisateur quittele programme (en tapant quit ou en produisant le caractère de fin de fichier ^D). La simplicitéfait la force de ce script : les programmes shell n’ont pas besoin d’être compliqués pour êtreutiles !

Exécuter le scriptL’exécution de ce script est aisée puisqu’il s’agit, par défaut, d’un outil interactif qui demandeà l’utilisateur ce qu’il souhaite faire. Si vous lui passez des arguments, il les transmet à lacommande scriptbc.

Les résultats

scale) scale=$args ;; *) scriptbc -p $scale "$command" "$args" ;; esac echo -n "calc> "done echo "" exit 0

$ calc 150 / 3.542.85$ calcCalc - une calculatrice simple. Tapez «help» pour avoir l'aide, «quit» pour quitter.calc> help Outre des fonctions mathématiques classiques, calc connaît aussi: a % b reste de la division entière a/b a ^ b exponentielle: a élevée à la puissance b s(x) sinus de x, x étant exprimé en radians c(x) cosinus de x, x étant exprimé en radians a(x) arctangente de x, renvoie des radians l(x) logarithme naturel de x e(x) exponentielle de x

100 scripts shell Unix76

Copyright ©

2004 Groupe E

yrolles

N°25 – Vérifier l’orthographe de certains motsLes programmes sophistiqués comme StarOffice, OpenOffice.org et Microsoft Wordcomportent des correcteurs orthographiques, mais aucun d’entre eux n’est capable des’acquitter simplement de la tâche rudimentaire qui consiste à vérifier l’orthographe d’un mot.

Par ailleurs, la plupart des systèmes Unix proposent un paquetage de correcteur qui fonc-tionne relativement bien, mais dont l’interface est simpliste. Si vous disposez d’un fichier oud’un flux de données en entrée, ces paquetages génèrent une longue liste de toutes les fautespotentielles. Certains comportent des applications de correcteur orthographique interactives.Pourtant, là encore, aucun d’entre eux ne propose de méthode simple de vérification.

Le code

j(n,x) fonction de Bessel d'ordre n de x scale N affiche N chiffres après la virgule (par défaut: 2)calc> 54354 ^ 3160581137553864calc> quit$

INFO Vous ne disposez pas de correcteur orthographique ?

Certaines distributions d’Unix ne proposent pas de paquetage de ce type (et pourtant ellesdevraient toutes le faire, l’espace disque est tellement bon marché à l’heure actuelle !). Le caséchéant, installez ispell avec le « dictionnaire » français (paquetage ifrench-gut sousDebian GNU/Linux), ou epelle. Ces produits sont disponibles sur http://fmg-www.cs.ucla.edu/geoff/ispell.html, http://fmg-www.cs.ucla.edu/geoff/ispell-dictionaries.html et http://www.iist.unu.edu/~alumni/software/other/inria/www/epelle/index-fra.htm.

#!/bin/sh# checkspelling - Contrôle l'orthographe d'un mot. spell="ispell -l -d french" # si vous avez installé ispell # et le dictionnaire français # sinon, utilisez un équivalent if [ $# -lt 1 ]; then echo "Syntaxe: $0 mot ou mots" >&2; exit 1 fi for word do

Créer des utilitairesCHAPITRE 3

77

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Exécuter le scriptPour utiliser ce script, il suffit de spécifier un ou plusieurs mots comme argument de lacommande checkspelling (correcteur orthographique).

Les résultatsIl est désormais facile de retrouver l’orthographe exacte du mot « épeler » :

Pour aller plus loinUn utilitaire de contrôle d’orthographe peut être utilisé de nombreuses façons. D’ailleursispell vous permet déjà de procéder à la plupart de ces opérations annexes. C’est l’arbre quicache la forêt, comme nous le verrons au script suivant.

N°26 – Vérifier l’orthographe interactivement avec shpellIl est parfois utile de contrôler l’orthographe d’un mot isolé, bien qu’il soit plus fréquent devérifier l’orthographe d’un texte complet, par exemple via l’utilitaire ispell s’il est installé(malgré son interface déconcertante aux yeux de certains). Si vous ne disposez pas d’ispell,utilisez des paquetages de correcteur orthographique plus élémentaires, pauvres en fonction-nalités, qui se contentent de répondre à la question « Ce mot est-il correct ? ». Quelle que soitvotre situation, vous pouvez également mettre en œuvre une solution qui consiste à contrôleret à corriger toutes les fautes d’orthographe d’un fichier. Le script shell suivant réalise cetteopération.

if [ -z $(echo $word | $spell) ] ; then echo "$word: bien écrit." else echo "$word: mal écrit." fi done exit 0

$ checkspelling épeler épellerépeler: bien écrit.épeller: mal écrit.

100 scripts shell Unix78

Copyright ©

2004 Groupe E

yrolles

Le code

#!/bin/sh# shpell - Programme de correcteur orthographique interactif qui vous# permet de parcourir un à un tous les mots suspects du document,# indiquer ceux que vous souhaitez corriger et de quelle manière, et# qui applique ensuite ces modifications au fichier.# La version originale du fichier est conservée sous le suffixe .shp,# et la version corrigée remplace le fichier de départ. # Vous remarquerez qu'il faut disposer d'une commande «spell» standard# pour que ceci fonctionne; vous devrez donc parfois# installer aspell, ispell ou pspell sur votre système. tempfile="/tmp/$0.$$"changerequests="/tmp/$0.$$.sed"spell="ispell -l -d french" # à modifier en fonction de votre installation trap "rm -f $tempfile $changerequests" EXIT HUP INT QUIT TERM # Inclut les définitions de séquences de couleurs ANSI . script-library.shinitializeANSI getfix(){# Demande à l'utilisateur de spécifier une correction. Si le mot proposé# est également mal écrit, la fonction s'appelle elle-même, avec une# récursivité de niveau 2. Ceci peut se poursuivre indéfiniment, mais # garder la trace du niveau d'imbrication nous permet de n'émettre le # message du «mot de remplacement» qu'au niveau 1. word=$1 filename=$2 misspelled=1 while [ $misspelled -eq 1 ] do echo ""; echo "${boldon}Mot «${word}» mal écrit:${boldoff}" grep -n $word $filename | sed -e 's/^/ /' -e "s/$word/$boldon$word$boldoff/g" echo -n "i)gnorer, q)uitter, ou taper un mot de remplacement: "

Créer des utilitairesCHAPITRE 3

79

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

read fix if [ "$fix" = "q" -o "$fix" = "quit" ] ; then echo "Fin du programme; aucune correction appliquée."; exit 0 elif [ "${fix%${fix#?}}" = "!" ] ; then misspelled=0 # l'utilisateur force la correction, # on cesse les vérifications echo "s/$word/${fix#?}/g" >> $changerequests elif [ "$fix" = "i" -o -z "$fix" ] ; then misspelled=0 else if [ ! -z "$(echo $fix | sed 's/[^ ]//g')" ] ; then misspelled=0 # quand on voit des blancs, on cesse la vérification echo "s/$word/$fix/g" >> $changerequests else # C'est le remplacement d'un mot, vérifions aussi son orthographe if [ ! -z "$(echo $fix | $spell)" ] ; then echo "" echo "*** Votre proposition de remplacement $fix est mal écrite." echo "*** Préfacez le mot de «!» pour l'imposer sans contrôle." else misspelled=0 # le mot suggéré est acceptable echo "s/$word/$fix/g" >> $changerequests fi fi fi done } ### Début du corps du script à proprement parlerif [ $# -lt 1 ] ; then echo "Syntaxe: $0 nom_de_fichier" >&2 ; exit 1 fi if [ ! -r $1 ] ; then echo "$0: je ne peux lire le fichier $1 et en contrôler l'orthographe" >&2 exit 1 fi # L'appel suivant remplit au passage le fichier $tempfileerrors="$($spell < $1 | tee $tempfile | wc -l | sed 's/[^[:digit:]]//g')" if [ $errors -eq 0 ] ; then echo "Aucune erreur d'orthographe détectée dans $1."; exit 0

100 scripts shell Unix80

Copyright ©

2004 Groupe E

yrolles

Dans le détailCe script repose sur la fonction getfix, qui affiche chaque erreur dans son contexte etdemande à l’utilisateur de proposer une correction ou d’ignorer l’erreur. Les conditionnellessophistiquées du script permettent à l’utilisateur de taper une correction pour la faute détectée,i pour l’ignorer ou q pour quitter le programme. Signalons que getfix est interactive : ellecontrôle l’orthographe des corrections proposées afin de vérifier si vous remplacez un motmal écrit par un autre. Si le script pense que la correction est également incorrecte, vouspouvez l’imposer en la faisant précéder du caractère !.

Les corrections sont stockées dans le script sed nommé $changerequests (modificationsrequises). Vous pouvez ainsi appliquer les changements au fichier une fois que l’utilisateur arevu toutes les fautes potentielles signalées par le script.

Signalons encore que la commande trap, insérée au début du script, garantit la destruction detous les fichiers temporaires créés au cours de l’exécution du code. Enfin, si vous examinezles dernières lignes du script, vous constatez que la version non corrigée du fichier est sauve-gardée avec un suffixe .shp, au cas où une opération ne fonctionnerait pas correctement. Il estconseillé d’anticiper tout problème potentiel, surtout avec des scripts qui interviennent direc-tement sur les fichiers fournis.

fi echo "Nous devons corriger $errors mots mal écrits dans le document."echo "Rappelez-vous, si vous êtes paresseux, que la réponse par "echo "défaut à l'invite du correcteur orthographique est «ignorer»." touch $changerequests for word in $(cat $tempfile) do getfix $word $1 1 done if [ $(wc -l < $changerequests) -gt 0 ] ; then sed -f $changerequests $1 > $1.new mv $1 $1.shp mv $1.new $1 echo Fini. $(wc -l < $changerequests) modifications effectuées. fi exit 0

Créer des utilitairesCHAPITRE 3

81

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Exécuter le scriptPour exécuter ce script, spécifiez en argument de la commande le nom du fichier dont l’ortho-graphe doit être vérifiée.

Les résultats

Il est impossible de les reproduire dans cet ouvrage, mais les séquences de couleur ANSI utili-sées à l’affichage mettent en évidence les mots (apparemment) mal écrits.

N°27 – Ajouter un dictionnaire local à spellLes scripts n°25 et 26, à l’instar de la plupart des implémentations de correcteurs orthographi-ques dans les distributions Unix standards, ne proposent pas à l’utilisateur d’ajouter des motsdans un dictionnaire personnel pour éviter de les voir apparaître systématiquement. Il estfacile d’ajouter cette fonctionnalité.

$ ./shpell 026-chaperon-fautes.txtNous devons corriger 5 mots mal écrits dans le document.Rappelez-vous, si vous êtes paresseux, que la réponse par défaut à l'invite du correcteur orthographique est «ignorer». Mot «gallette» mal écrit: 3:mère-grand, et lui porter une gallette avec un petit pot de beurre que mai)gnorer, q)uitter, ou taper un mot de remplacement: galette Mot «Demeure-t-elle» mal écrit: 4:mère lui envoie. – Demeure-t-elle bien loin? lui dit le loup. – Oh!i)gnorer, q)uitter, ou taper un mot de remplacement: Mot «chemin-ci» mal écrit: 8:chemin-ci, et toi par ce chemin-là, et nous verrons qui plus tôt yi)gnorer, q)uitter, ou taper un mot de remplacement: Mot «chemin-là» mal écrit: 8:chemin-ci, et toi par ce chemin-là, et nous verrons qui plus tôt yi)gnorer, q)uitter, ou taper un mot de remplacement: Mot «ceuillir» mal écrit: 11:s'amusant à ceuillir des noisettes, à courir après des papillons, et ài)gnorer, q)uitter, ou taper un mot de remplacement: cueillirFini. 2 modifications effectuées.

100 scripts shell Unix82

Copyright ©

2004 Groupe E

yrolles

Le code

#!/bin/sh# spelldict - Utilise «ispell» et des filtres pour contrôler facilement,# en ligne de commande, l'orthographe d'un fichier. # Il est inévitable que certains mots soient signalés à tort comme# incorrects. Sauvez-les simplement dans un fichier, un par ligne, # et assurez-vous que la variable «okaywords» pointe vers ce fichier. okaywords="$HOME/.okaywords" tempout="/tmp/spell.tmp.$$" spell="ispell -d french" # à adapter selon les cas trap "/bin/rm -f $tempout" EXIT if [ -z "$1" ] ; then echo "Syntaxe: spelldict fichier" >&2; exit 1 elif [ ! -f $okaywords ] ; then echo "Dictionnaire personnel introuvable." >&2 echo "Créez-en un et exécutez cette commande à nouveau." >&2 echo "Votre fichier dictionnaire: «$okaywords»." >&2 exit 1fi for filenamedo $spell -a < $filename | \ grep -v '@(#)' | sed "s/\'//g" | \ awk '{ if (length($0) > 15 && length($2) > 2) print $2}' | \ grep -vif $okaywords | \ grep '[[:lower:]]' | grep -v '[[:digit:]]' | sort -u | \ sed 's/^/ /' > $tempout if [ -s $tempout ] ; then sed "s/^/${filename}: /" $tempout fi done exit 0

Créer des utilitairesCHAPITRE 3

83

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Dans le détailSur le modèle du correcteur orthographique de Microsoft Office, ce script ne se contente pasde reconnaître un dictionnaire défini par l’utilisateur et composé de mots correctement écrits,mais signalés comme erronés par le programme. Il ignore également les mots écrits complè-tement en majuscules (probablement des acronymes) et ceux qui contiennent un chiffre.

Dans le cas présent, le code utilise ispell en mode filtre (-a). Le programme lit les mots surson entrée standard stdin, il les examine et reproduit uniquement les mots suspects sur sasortie standard. La plupart des autres correcteurs orthographiques sont capables de déterminerque stdin n’est pas le clavier et que le mode filtre doit donc être utilisé pour la lecture. Si votresystème dispose d’un autre utilitaire, lisez sa page de manuel pour découvrir le ou les optionsà fournir.

Exécuter le scriptCe script attend un ou plusieurs noms de fichiers sur la ligne de commande.

Les résultatsÀ partir d’un dictionnaire personnel vide et d’un extrait du Petit chaperon rouge, vous obtenezle résultat suivant :

Trois de ces mots ne sont pas des fautes de frappe ; je vais donc les ajouter à mon dictionnairepersonnel via la commande echo qui entre les termes à la fin du fichier okaywords (motscorrects) :

Voici les nouveaux résultats produits par le fichier quand il dispose du dictionnaire étendu :

$ spelldict 027-chaperon.txt027-chaperon.txt: Demeure-t-elle027-chaperon.txt: beure027-chaperon.txt: chevillette027-chaperon.txt: demeurrait027-chaperon.txt: s'alla

$ echo "Demeure-t-elle" >> /.okaywords$ echo "chevillette" >> /.okaywords$ echo "s'alla" >> /.okaywords

$ spelldict 027-chaperon.txt027-chaperon.txt: beure027-chaperon.txt: demeurrait

100 scripts shell Unix84

Copyright ©

2004 Groupe E

yrolles

N°28 – Convertir les températuresCe script manipule un certain nombre de formules mathématiques et un format d’entrée inha-bituel permettant de convertir les valeurs de températures exprimées en degrés Celsius endegrés Fahrenheit et en Kelvin. Dans cet ouvrage, nous n’avons pas encore eu recours auxmathématiques complexes dans un script. Ici, nous nous servons du script n°9, qui a donnénaissance au programme scriptbc, et nous reprenons l’idée de faire passer une équation à bcvia un tuyau.

Le code

#!/bin/sh # convertatemp - Script de conversion de températures qui permet à# l'utilisateur de taper une température en degrés Celsius, Fahrenheit,# ou Kelvin, et qui la transforme dans les deux autres unités. if [ $# -eq 0 ] ; then cat << EOF >&2 Syntaxe: $0 <température>[F|C|K] où le suffixe: C indique que la donnée est en degrés Celsius (situation par défaut) F indique que la donnée est en degrés Fahrenheit K indique que la donnée est en KelvinEOF exit 1 fi unit="$(echo $1|sed -e 's/[-[[:digit:]]*//g' | tr '[:lower:]' '[:upper:]' )" temp="$(echo $1|sed -e 's/[^-[[:digit:]]*//g')" case ${unit:=C} in F ) # formule de conversion Fahrenheit -> Celsius: C = (F - 32) / 1.8 farn="$temp" cels="$(echo "scale=2;($farn - 32) / 1.8" | bc)" kelv="$(echo "scale=2;$cels + 273.15" | bc)" ;; C ) # formule de conversion Celsius -> Fahrenheit: F = (9/5)*C+32 cels=$temp kelv="$(echo "scale=2;$cels + 273.15" | bc)" farn="$(echo "scale=2;((9/5) * $cels) + 32" | bc)" ;;

Créer des utilitairesCHAPITRE 3

85

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Exécuter le scriptLe côté intuitif du format d’entrée de ce script me semble intéressant, même s’il est inhabituelpour une commande Unix. Les données sont tapées sous forme de valeur numérique et unsuffixe facultatif indique l’unité employée. Pour connaître l’équivalent de 100 degrés Fahren-heit en degrés Celsius et en Kelvin, tapez 100F. Pour savoir à quoi correspondent 100 Kelvinen degrés Celsius ou Fahrenheit, précisez 100K. Le suffixe C indique des degrés Celsius ; ils’agit également de l’unité utilisée par défaut, en l’absence de précision fournie par l’utilisa-teur.

L’approche qui consiste à utiliser les suffixes d’une lettre sera reprise au script n°66 deconversion des devises.

Les résultats

K ) # Celsius = Kelvin - 273.15, puis utiliser la formule Cels -> Fahr kelv=$temp cels="$(echo "scale=2; $kelv - 273.15" | bc)" farn="$(echo "scale=2; ((9/5) * $cels) + 32" | bc)"esac echo "Fahrenheit = $farn" echo "Celsius = $cels" echo "Kelvin = $kelv" exit 0

$ convertatemp 100Fahrenheit = 212.00Celsius = 100Kelvin = 373.15$ convertatemp 212FFahrenheit = 212Celsius = 100.00Kelvin = 373.15$ convertatemp 100KFahrenheit = -279.67Celsius = -173.15Kelvin = 100

100 scripts shell Unix86

Copyright ©

2004 Groupe E

yrolles

Pour aller plus loinPrévoyez quelques options de ligne de commande pour que ce script génère un format desortie succinct et puisse être utilisé depuis d’autres programmes. L’appel convertatemp –c 100f est capable de convertir 100 degrés Fahrenheit en Celsius.

N°29 – Calculer les remboursements d’un prêtMaintenant que nous savons convertir les températures, passons à un autre calcul fréquent, àsavoir l’estimation du montant des remboursements d’un prêt. Le script qui suit répond à laquestion « Que faire de l’argent qui me reste ? », tout au moins quand tout va bien.

La formule qui permet de calculer les remboursements en tenant compte du capital, du tauxd’intérêt et la durée du prêt est relativement complexe. Cependant, une utilisation judicieusedes variables du shell viendra à bout du monstre, et le rendra nettement plus simple.

Le code

#!/bin/sh # loancalc - Étant donné un capital, un taux d'intérêt, et une durée de# prêt (en années), calcule le montant de la traite mensuelle. # La formule est: M = P * ( J / (1 - (1 + T) ** -N))# où P est le capital, J le taux d'intérêt mensuel, N la durée (en mois)## Les utilisateurs fournissent généralement P, I (taux d'intérêt annuel)# et L (la durée, exprimée en années). . script-library.sh if [ $# -ne 3 ] ; then echo "Syntaxe: $0 <capital> <taux d'intérêt> <années>" >&2 exit 1fi P=$1 I=$2 L=$3J="$(scriptbc -p 8 $I / \( 12 \* 100 \) )"N="$(( $L * 12 ))"M="$(scriptbc -p 8 $P \* \( $J / \(1 - \(1 + $J\) \^ -$N\) \) )" # Un léger nettoyage de la valeur calculée:

Créer des utilitairesCHAPITRE 3

87

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Exécuter le scriptCe script réduit a besoin de trois paramètres : le montant du prêt (ou capital), son tauxd’intérêt et sa durée (en années).

Les résultatsJ’ai repéré la dernière Volvo XC90 et je me demande à combien s’élèveront mes rembourse-ments mensuels si j’achète cette voiture. Elle coûte environ 40 000 EUR et le taux d’intérêtannuel pour un prêt automobile est actuellement de 6,75 %. Pour comparer un prêt sur quatreans et un autre sur cinq ans, rien de plus facile :

Si je peux faire face aux traites légèrement plus élevées du prêt sur quatre ans, la voiture estpayée et le montant total remboursé (montant mensuel multiplié par le nombre de traites) estnettement moins important. Pour calculer l’économie ainsi réalisée, je peux me servir duscript n°24 qui crée une calculatrice interactive :

Et voilà, avec les 1 485,72 EUR économisés, je peux m’offrir un bel ordinateur portable !

dollars="$(echo $M | cut -d. -f1)"cents="$(echo $M | cut -d. -f2 | cut -c1-2)" cat << EOFUn prêt de $(nicenumber $P 1 ) EUR sur $L ans à $I% d'intérêtsuppose un remboursement de $dollars,$cents EUR chaque moispendant toute la durée du prêt (soit $N traites).EOF exit 0

$ loancalc 40000 6.75 4Un prêt de 40,000 EUR sur 4 ans à 6.75% d'intérêtsuppose un remboursement de 953,21 EUR chaque moispendant toute la durée du prêt (soit 48 traites).$ loancalc 40000 6.75 5Un prêt de 40,000 EUR sur 5 ans à 6.75% d'intérêtsuppose un remboursement de 787,33 EUR chaque moispendant toute la durée du prêt (soit 60 traites).

$ calc '(787.33 * 60) - (953.21 * 48)'1485.72

100 scripts shell Unix88

Copyright ©

2004 Groupe E

yrolles

Pour aller plus loinNous n’analyserons pas ici la formule mathématique, mais il est intéressant de constater queles scripts shell permettent d’implémenter directement les équations les plus ardues.

Il est possible d’effectuer la totalité du calcul en fournissant un flux de données unique à bc,puisque ce programme permet également d’utiliser des variables. Cependant, vous ne pouvezpas manipuler les valeurs intermédiaires depuis le seul script. Pour illustrer ce type de traite-ment, utilisez le code suivant, qui divise en deux parties le montant de la traite mensuelle ets’assure que le formatage de la valeur monétaire est correct :

Comme dans la plupart des scripts de ce manuel, la commande cut est très utile. La deuxièmeligne de ce code isole la partie fractionnaire du montant de la traite mensuelle et coupe tout cequi suit le deuxième chiffre. Dans une situation réelle, il est préférable d’arrondir par défautou par excès, selon la valeur du troisième chiffre, plutôt que d’arrondir par défaut dans tousles cas. Vous serez parfois surpris de la facilité avec laquelle cette modification est appliquée :il suffit d’ajouter 0.005 centimes à la valeur avant de conserver uniquement les deux premierschiffres.

Vous pouvez également écrire ce script pour qu’il demande à l’utilisateur les valeurs dechaque champ si elles n’ont pas été fournies. Et pourquoi ne pas créer une version plus sophis-tiquée et plus utile encore, qui permettrait à l’utilisateur d’entrer n’importe quelle combi-naison de trois valeurs sélectionnées parmi les quatre disponibles (capital, taux d’intérêt,nombre de traites, et montant mensuel des traites) et calculerait la quatrième ? De cettemanière, en sachant que l’utilisateur peut se permettre des traites ne dépassant pas 500 EURet que la durée maximale d’un prêt à 6 % est de 5 ans, vous pouvez déduire le montantmaximal du capital susceptible d’être emprunté dans ces conditions.

N°30 – Implémenter un agendaCe script se compose de deux programmes qui implémentent un calendrier de base. Lepremier script, addagenda, permet de préciser un jour de la semaine ou une date dans l’annéepour les événements récurrents, ainsi qu’une date complète pour les événements uniques.Toutes ces dates sont validées et sauvegardées dans le fichier .agenda de votre répertoirepersonnel. Elles sont accompagnées d’une description sur une ligne de l’événement concerné.Quant au deuxième programme, agenda, il examine tous les événements connus et afficheceux qui sont associés à la date du jour.

Ce type d’outil vous évite notamment d’oublier les anniversaires et autres fêtes. Il vous épar-gnera bien des grincements de dents !

dollars="$(echo $M | cut -d. -f1)" cents="$(echo $M | cut -d. -f2 | cut -c1-2)"

Créer des utilitairesCHAPITRE 3

89

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Le code

#!/bin/sh# addagenda - Invite l'utilisateur à inclure un nouvel événement pour# le script agenda. agendafile="$HOME/.agenda" isDayName(){ # renvoie 0 si tout va bien, 1 en cas d'erreur case $(echo $1 | tr '[[:upper:]]' '[[:lower:]]') in sun*|mon*|tue*|wed*|thu*|fri*|sat*) retval=0 ;; * ) retval=1 ;; esac return $retval} isMonthName() { case $(echo $1 | tr '[[:upper:]]' '[[:lower:]]') in jan*|feb*|mar*|apr*|may*|jun*) return 0 ;; jul*|aug*|sep*|oct*|nov*|dec*) return 0 ;; * ) return 1 ;; esac} normalize(){ # Renvoie la chaîne en mettant une majuscule à l'initiale et en passant les # deux lettres suivantes en minuscules. echo -n $1 | cut -c1 | tr '[[:lower:]]' '[[:upper:]]' echo $1 | cut -c2-3| tr '[[:upper:]]' '[[:lower:]]'} if [ ! -w $HOME ] ; then echo "$0: je ne peux écrire dans votre répertoire personnel ($HOME)" >&2 exit 1fi echo "Agenda: Le pense-bête d'Unix"echo " note: tapez les dates en anglais"echo -n "Date de l'événement (jour mois, jour mois année, ou nom du jour): "

100 scripts shell Unix90

Copyright ©

2004 Groupe E

yrolles

read word1 word2 word3 junk if isDayName $word1 ; then if [ ! -z "$word2" ] ; then echo "Mauvais format de nom de jour: ne précisez que le nom du jour." >&2 exit 1 fi date="$(normalize $word1)" else if [ -z "$word2" ] ; then echo "Mauvais format de nom de jour: nom de jour inconnu" >&2 exit 1 fi if [ ! -z "$(echo $word1|sed 's/[[:digit:]]//g')" ] ; then echo "Mauvais format de date: spécifiez d'abord le nom du jour puis son numéro" >&2 exit 1 fi if [ "$word1" -lt 1 -o "$word1" -gt 31 ] ; then echo "Mauvais format de date: le numéro du jour doit être compris entre 1 et 31" >&2 exit 1 fi if ! isMonthName $word2 ; then echo "Mauvais format de date: nom de mois inconnu." >&2 exit 1 fi word2="$(normalize $word2)" if [ -z "$word3" ] ; then date="$word1$word2" else if [ ! -z "$(echo $word3|sed 's/[[:digit:]]//g')" ] ; then echo "Mauvais format de date: le troisième champ doit être une année." >&2 exit 1 elif [ $word3 -lt 2000 -o $word3 -gt 2500 ] ; then

Créer des utilitairesCHAPITRE 3

91

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Le second script, plus court, est appelé plus souvent :

echo "Mauvais format de date: l'année doit être comprise entre 2000 et 2500" >&2 exit 1 fi date="$word1$word2$word3" fi fi echo -n "Description sur une ligne: " read description # Prêt à consigner les données dans le fichier echo "$(echo $date|sed 's/ //g')|$description" >> $agendafile exit 0

#!/bin/sh # agenda - Examine le fichier .agenda de l'utilisateur à la recherche# d'événements concernant le jour courant. agendafile="$HOME/.agenda" checkDate(){ # Crée les valeurs par défaut qui pourront correspondre au jour courant weekday=$1 day=$2 month=$3 year=$4 format1="$weekday" format2="$day$month" format3="$day$month$year" # et on parcourt le fichier en comparant les dates... IFS="|" # les lectures seront naturellement coupées à l'IFS echo "L'agenda prévoit ce jour:" while read date description ; do if [ "$date" = "$format1" -o "$date" = "$format2" -o "$date" = "$format3" ] then echo " $description" fi

100 scripts shell Unix92

Copyright ©

2004 Groupe E

yrolles

Dans le détailLe script agenda reconnaît trois types d’événements : les échéances hebdomadaires (parexemple, chaque mercredi), celles qui se produisent tous les ans (par exemple, tous les 3 août)et les manifestations uniques (par exemple, le 1er janvier 2010). Lors de leur sauvegarde dansle fichier d’agenda, les dates spécifiées sont normalisées et compactées : le trois août (August)apparaît sous la forme « 3Aug », et jeudi (Thursday) devient « Thu ». La fonction normalizeeffectue cette opération :

Toute valeur tapée se trouve ainsi réduite à trois caractères, à savoir une majuscule, puis deuxminuscules. Ce format correspond aux valeurs abrégées standards de jour et de nom de moisutilisées pour la sortie de la commande date (quand elle fonctionne en anglais !). Il est indis-pensable au bon fonctionnement du script agenda.

done < $agendafile } if [ ! -e $agendafile ] ; then echo "$0: Vous ne semblez pas posséder un fichier .agenda" >&2 echo "Pour remédier à cela, veuillez utiliser «addagenda» pour" >&2 echo "enregistrer des événements." >&2 exit 1fi # Voyons maintenant quelle est la date du jour... eval $(date "+weekday=\"%a\" month=\"%b\" day=\"%e\" year=\"%G\"") day="$(echo $day|sed 's/ //g')" # on enlève les éventuels blancs initiaux checkDate $weekday $day $month $year exit 0

normalize(){ # Renvoie la chaîne en mettant en majuscule l'initiale et en passant les # deux lettres suivantes en minuscules. echo -n $1 | cut -c1 | tr '[[:lower:]]' '[[:upper:]]' echo $1 | cut -c2-3| tr '[[:upper:]]' '[[:lower:]]'}

Créer des utilitairesCHAPITRE 3

93

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

Le script agenda recherche des événements en transformant la date du jour en trois chaînespossibles (nom du jour, jour et mois, jour et mois et année). Il recherche ensuite chacune deces chaînes dans le fichier de données .agenda. S’il trouve quelque chose, il affiche cet événe-ment. Bien qu’il soit particulièrement long, le script addagenda reste relativement simple.

Vous gagnerez à utiliser eval pour stocker dans des variables chacun des quatre paramètres dedate :

Vous pouvez également extraire ces valeurs séparément (en tapant, par exemple,weekday="$(date +%a)"), mais l’opération échoue si le jour change au cours de l’exécution del’un des quatre appels à la commande date. Bien que cette situation soit peu fréquente, il estpréférable de l’utiliser une seule fois. Dans tous les cas, cette commande renvoie un numérode jour préfixé d’un blanc indésirable. C’est pourquoi la ligne de code qui suit celle-ci détruitles blancs qui précèdent la valeur proprement dite, avant de passer à la suite.

Exécuter le scriptLe script addagenda demande à l’utilisateur la date d’un nouvel événement. S’il accepte leformat spécifié, il revient à la charge en réclamant une description de cet événement sur uneligne.

Le script d’accompagnement agenda ne prend aucun paramètre et produit la liste de tous lesévénements prévus ce jour.

Les résultatsPour observer le fonctionnement de ce duo, remplissons la base de données de quelquesévénements :

eval $(date "+weekday=\"%a\" month=\"%b\" day=\"%e\" year=\"%G\"")

$ addagendaAgenda: Le pense-bête d'Unix note: tapez les dates en anglaisDate de l'événement (jour mois, jour mois année, ou nom du jour): 31 OctoberDescription en une ligne: Halloween$ addagendaAgenda: Le pense-bête d'Unix note: tapez les dates en anglaisDate de l'événement (jour mois, jour mois année, ou nom du jour): 30 MarchDescription en une ligne: avant-dernier jour de mars$ addagendaAgenda: Le pense-bête d'Unix

100 scripts shell Unix94

Copyright ©

2004 Groupe E

yrolles

Le script agenda fournit désormais un pense-bête court et pratique qui vous permet de prendreconnaissance des événements du jour :

Notez que le script a pris en compte les entrées formatées jour+mois, jour de la semaine, etjour+mois+année. Par souci d’exhaustivité, nous donnons ici le fichier .agenda associé, quicomporte quelques entrées supplémentaires :

Pour aller plus loinCe script ne fait qu’effleurer un sujet vaste et complexe. Par exemple, il serait intéressant dele faire travailler quelques jours à l’avance, grâce à quelques calculs sur la date dans le scriptagenda. Si vous disposez de la version GNU de la commande date, ces calculs sont faciles à

note: tapez les dates en anglaisDate de l'événement (jour mois, jour mois année, ou nom du jour): SundayDescription en une ligne: grasse matinée (avec de la chance...)$ addagendaAgenda: Le pense-bête d'Unix note: tapez les dates en anglaisDate de l'événement (jour mois, jour mois année, ou nom du jour): marc 30 03Mauvais format de date: spécifiez d'abord le nom du jour puis son numéro$ addagendaAgenda: Le pense-bête d'Unix note: tapez les dates en anglaisDate de l'événement (jour mois, jour mois année, ou nom du jour): 30 march 2003Description en une ligne: envoyer un SMS à Marvin pour le voir à dîner

$ agenda L'agenda prévoit ce jour: avant-dernier jour de mars grasse matinée (avec de la chance...) envoyer un SMS à Marvin pour le dîner

$ cat /.agenda14Feb|Saint Valentin25Dec|Noël3Aug|Anniversaire de David14Jul|Fête nationale (en France)31Oct|Halloween30Mar|avant-dernier jour de marsSun|grasse matinée (avec de la chance...)30Mar2003|envoyer un SMS à Marvin pour le voir à dîner

Créer des utilitairesCHAPITRE 3

95

Cop

yrig

ht ©

200

4 G

roup

e E

yrol

les

effectuer (ex : today+2 days, ou « aujourd’hui plus deux jours »). Dans le cas contraire, vousdevez avoir recours à un script shell complexe pour déterminer la date du jour qui suit.

Autre fonctionnalité qu’il serait encore plus simple de mettre en œuvre : demander au scriptagenda d’écrire « Rien de prévu ce jour » si aucun événement ne correspond à la date du jour,plutôt que « L’agenda prévoit ce jour : » suivi d’un espace vide.

Vous pouvez également employer ce script sur un système Unix pour rappeler à tous les utili-sateurs du système les moments des sauvegardes, les dates de fermeture de l’entreprise et lesanniversaires des employés. Pour cela, il suffit de faire pointer le script agenda installé sur lamachine de chaque utilisateur vers un fichier .agenda partagé et en lecture seule, puisd’insérer un appel à ce script dans le fichier .login de chaque utilisateur, ou dans un fichiersimilaire.