\chapter{scripting} Qu'est-ce que le \textsl{scripting} ? C'est l'art de coller entre eux divers outils logiciels afin de réaliser une tache donnée. Le "collage" est fait par un \textbf{script}, lequel est un fichier texte, écrit dans divers langages (plus ou moins spécifiques) et qui sera lu et exécuté par un interpréteur. Je ne vais pas revenir sur l'art du shebang, si vous ne le connaissez pas, c'est expliqué page \pageref{shebang}. En bref, c'est la manière dont le script sélectionne le bon interpréteur lors de son lancement. Quels sont les langages courrament utilisés pour faire du script ? Il y a une bonne poignée de réponses à ça. La première étant souvent « Use The Shell ! », et la seconde « tu as songé à awk ? », ce qui est tout aussi sensé. Le shell étant dégrossi page \pageref{chap:shell}, passons directement au langage Awk. % =============================================================== \section{Awk} \index{Awk} Awk est un langage de programmation crée par Aho, Kernighan, and Weinberger% \footnote{The AWK Programming Language, Alfred V. Aho, Brian W. Kernighan, Peter J. Weinberger, Addison-Wesley, 1988. ISBN 0-201-07981-X. }. Son originalité vient du fait qu'il a été conçu principalement pour traiter ligne par ligne des fichiers tabulés. C'est son domaine de prédilection, autant en profiter. Quelques \textsl{oneliners} de bon aloi pour vous donner une idée des possibilités du langage\dots \begin{verbatim} cat { print $0 } or just 1 grep pattern /pattern/ head -n 5 NR <= 5 cut -f1 { print $1 } tr a-z A-Z { print toupper($0) } sed 's/hi/ho/g' gsub(/hi/,"ho") wc -l END { print NR } \end{verbatim} Vous pouvez déja constater une certaine élégance portée par une grande simplicité logique, une sorte d'axiome de base, de méthologie très \textsc{kiss} : on va procéder en quelque sorte « demi-dalle par demi-dalle ». % =============================================================== \subsection{Un exemple simple} À partir d'un jeu de données structurées, nous allons générer un fichier \texttt{.inc} contenant la description en SDL\index{SDL}\footnote{SDL: Scene Description Language} d'un objet pour Povray\index{Povray}. Un cas d'école : un élément par ligne, les valeurs sont séparées par des espaces et/ou des tabulations. \lstinputlisting[]{code/awk/dataset} Ces données sont les coordonnées \textsc{x,y,z} et le rayon d'une petite collection de bubulles. Pratiquement, une représentation sommaire d'une sphère de povray. Le fichier à générer est en trois partie : l'en-tête, la liste des bubulles\index{bubulle} et l'en-pied, ce qui est bien raccord avec la structure de déroulement d'un script Awk, comme nous allons le voir ici-même~: \lstinputlisting[]{code/awk/mkunion.awk} La première ligne est pour le traditionnel \textsl{shebang}\index{shebang}, avec l'option \texttt{-f} pour que le contenu du script soit lu par l'interpréteur Awk dès son lancement. Ensuite, nous trouvons trois blocs délimités par des accolades, deux d'entre eux étant précédés d'une « instruction ». Le premier bloc, avec le mot-clef \textsc{BEGIN}, est exécuté avant la lecture de la première ligne des données en entrée. Ce qui est le bon moment pour initialiser des variables. Nous l'utilisons pour créer l'en-tête d'un descripteur d'objet pour Povray. Le second bloc (sans label) est exécuté pour chaque ligne lue. Et c'est ici que nous trouverons la magie. La ligne lue depuis l'entrée a été découpée selon le séparateur FS, et les tranches sont connues sous les noms de \$1, \$2, ... \$N (la ligne entière étant \$0) que nous utilisons dans la génération de la bubulle. Et le troisième bloc (\textsc{END}) sera exécuté à la fin, après la lecture et le traitement du dernier enregistrement, qui est dans notre cas la dernière ligne. Et à l'exécution~: \begin{verbatim} tth@redlady:~/Devel/TetaTricks/code/awk$ ./mkunion.awk < dataset #declare Bubulles = object { union { sphere { <17.000000, 9.000000, 4.000000>, 1.500000 } sphere { <11.000000, 0.800000, 2.300000>, 0.989000 } sphere { <0.000000, 0.000000, 0.000000>, 1.000000 } } } // 3 bubulles \end{verbatim} % =============================================================== \subsection{Mais ce n'est pas tout !} Ce premier exemple nous a montré comment, avec quelques lignes de code facile à comprendre, transformer des données et faire quelques calculs avec ces données. Nous avons vu le découpage de la ligne d'entrée, mais ce n'est pas tout, je suis passé très vite sur ce sont ces "labels" dont j'ai parlé. Ce ne sont absolument pas des labels, ni des mot-clefs, mais quelque chose de bien plus puissant. C'est le mécanisme qui permet de sélectionner les lignes sur lesquelles nous voulons appliquer un traitement. Nous avons déja vu \textsc{BEGIN} et \textsc{END}, pour lancer du code avant-le-début et/ou après-la-fin. Mais nous pouvons mettre des bouts de code donnant un résultat booléen, oui/non, qui conditionnera l'exécution du bloc de code ainsi préfixé\footnote{J'ai l'impression de pas être très clair ?}, ce qui nous donnera des possibilités de filtrage surpuissantes. Par exemple, nous ne voulons pas de bubulle trop petite, il suffit de précéder le second bloc de l'exemple déja vu par un test sur la taille qui est dans le quatrième champ du fichier d'entrée~: \begin{verbatim} $4 > 0.999 { printf(" sphere { <%f, %f, %f>, %f }\n", \ $1, $2, $3, $4 ) } \end{verbatim} Vous comprenez maintenant les deux plus importantes choses que l'on peut trouver dans Awk (/me fan). XXX to be continued \index{XXX} % =============================================================== \subsection{Définir une fonction} Bien, nous savons maintenant générer des bubulles avec un filtrage sur la taille, mais nous voudrions maintenant procéder à des calculs sur les données que nous lisons. Deux choix s'offrent à nous, soit faire ça directement dans le deuxième bloc, soit utiliser un sous-programme dédié. Pour des raisons aussi bien didactiques que de bon sens, nous allons opter pour la seconde solution. Mais voyons d'abord la syntaxe d'une fonction, avec en prime une petite astuce: si vous voulez utiliser Awk dans devoir lui fournir de données en entrée, c'est simple, mettez tout dans le bloc \textsc{BEGIN}. \lstinputlisting[]{code/awk/demo-func.awk} \begin{verbatim} tth@redlady:~/Devel/TetaTricks/code/awk$ ./demo-func.awk ---- demo fonction ---- sin(1.000000) = 0.841471 distance from center = 0.707107 \end{verbatim} La deuxième fonction demande quelques explications, puisqu'elle met en œuvre un « awkisme » de bon aloi. En effet, Awk ne connait pas les variables locales à une fonction, c'est-à-dire connues seulement à l'intérieur de celle-ci. % =============================================================== \subsection{Les variables} Et puisque on en parle... % =============================================================== \subsection{Pattern filtering} \index{pattern} Wesh, regexp. % ===============================================================