Formation complet Perl

Problème à signaler:

Télécharger



★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Table Des Mati?res

INTRODUCTION                                                                                                                                                                         3

           DIS, C’ESTQUOI PERL?                                                                                                                                                        3

                T’ASPASENCORE PERLSURTAMACHINE?                                                                   

                                                   4

1.  LES PRINCIPES ESSENTIELS DE PERL      5

1.1.  POURCOMMENCER    7

1.2.  LESLISTES       14

1.3.  L’INTERPOLATIONDEVARIABLE    19

1.4.  LASELECTIONPARLES PATTERNS : LE MATCHING       20

1.5.  LESTABLEAUXASSOCIATIFS           22

. PERL EN DETAIL           23

2.1.   LESVARIABLESSCALAIRES           25

2.2.   LESLISTESETLESTABLEAUX         31

2.3.   STRUCTURESDECONTROLE        37

2.4.   LESTABLEAUXASSOCIATIFS        41

2.5.   LESENTREES/SORTIES 45

2.6.   LESEXPRESSIONSREGULIERES    49

2.7.   LESFONCTIONS           59

2.8.   DIVERSESSTRUCTURESDECONTROLE         63

2.9.   LESMANIPULATEURSDEFICHIERSETLESTESTSSURLESFICHIERS 67

2.10.  LESFORMATS              73

2.11.  LESREPERTOIRES        81

2.12.  MANIPULATIONDEFICHIERSETDEREPERTOIRES        85

2.13.  LAGESTIONDEPROCESSUS          91

2.14.  AUTRESTRANSFORMATIONSSURLESDONNEES         97

2.15.  ACCESAUXDONNEESSYSTEME   103

2.16.  MANIPULATIONDEBASESDEDONNEESUTILISATEUR 109

2.17.  CONVERTIRD AUTRESLANGAGESEN PERL 115

2.18.  COMPLEMENTS           117

3.  EXEMPLE D APPLICATION        123

3.1.  UNSYSTEMEDERESERVATIONDEVOLS          125

3.2.  LEPROGRAMME PERL   127

3.3.  RESULTATS    137

4.  EXERCICES      143

4.1.  ENONCES       145

4.2.  SOLUTIONS    149

ANNEXE : LE GUIDE DE REFERENCE DE PERL                                                                                                             157


 

INTRODUCTION

DIS, C'EST QUOI PERL?

CrØØ tout d abord pour traiter efficacement du texte gr ce au «matching», Perl s’est dØveloppØ tant et si bien qu il est aujourd hui Øgalement un puissant langage de manipulation de fichiers: renommage, dØplacement, modification des droits; et de processus: crØation, destruction, communication, contr le de flux.

C est mŒme un langage rØseau, puisqu il offre la possibilitØ de communiquer avec des processus se trouvant sur d autres machines, par l intermØdiaire de sockets.

Perl permet donc d exØcuter d une fa on plus concise et lisible des t ches ordinairement effectuØes par un programme en C ou par l un des shells. C ne permet pas de faire tout ce que l on peut faire avec un shell, et vice versa. Perl comble cette lacune: c est une passerelle entre le C et les shells.

Perl fonctionne sous divers syst?mes d exploitation; on s intØressera en particulier son fonctionnement sous Unix.

C est un langage simple. Les structures et les types qu il emploie sont faciles comprendre et utiliser. Pas besoin de conna tre Perl en dØtail pour commencer Øcrire de petits programmes sympas. Pas de formule magique, non plus, pour compiler un programme Perl: il s exØcute comme un script shell.

Cependant, Perl est Øgalement un langage riche, puisqu il emprunte ses fonctionnalitØs au C, aux shells mais aussi sed et awk. Il permet de dØvelopper des programmes rapidement. En tant que langage script interprØtØ, il fournit un « feedback » immØdiat si une erreur est dØtectØe. De plus, un debugger symbolique est intØgrØ, qui comprend n’importe quelle expression Perl puisqu’il est Øcrit en Perl.

Dans ce document, les principes essentiels de Perl dans sa version 4.0 seront tout d’abord rapidement prØsentØs travers quelques exemples simples. Nous verrons ensuite plus en dØtail les structures et les types utilisØs par ce langage. Puis nous verrons un exemple de programmation en Perl.

Enfin, nous complØterons cette approche avec quelques exercices et un guide de rØfØrence, bien pratique pour vØrifier rapidement certains points en cas de doute.

Parall?lement , il existe une page man pour Perl: perl(1). Le newsgroup Usenet sur Perl est une source d’informations supplØmentaire. Il n’y a pas de question trop bŒte pour Œtre posØe il n’y a que des questions trop bŒtes pour qu’on y rØponde!

T'AS PAS ENCORE PERL SUR TA MACHINE?

Pas de panique! La gratuitØ Øtant la seule monnaie de l’art, Perl est gratuit.

Il est disponible par ftp anonyme sur les machines suivantes:

                                          192.48.96.2

128.146.8.60 128.149.1.143

Pour ceux qui ne sont pas sur Internet, Perl est disponible par uucp anonyme partir de uunet et de osu-cis.

Sur , Perl se trouve dans un unique fichier archive: .Z. Sur , il est dans le rØpertoire pub/perl.3.0; sur , il est dans perl/3.0 (bient t ce sera 4.0 pour les deux).

1.   LES PRINCIPES ESSENTIELS DE PERL


 

1.1. POUR COMMENCER

Perl est facile apprendre et simple d’utilisation. Il n’y a pas grand chose dire avant de dire effectivement ce que l’on veut dire. Par exemple, il n’y a aucune dØclaration effectuer avant d’Øcrire du code.

1.1.1. Les manipulateurs de fichiers (filehandle)

Voici un exemple de script Perl simple:

print "Donnez un nombre: \n";

$nombre = <STDIN>; print "Nombre lu : $nombre \n";

Ce script permet de lire une entrØe de l’utilisateur avec un retour d’information. La variable

$nombre re oit ce que l’utilisateur vient de taper; en effet, le symbole <STDIN> indique simplement qu’il faut lire la ligne courante de l’entrØe standard.

La commande print poss?de un param?tre optionnel indiquant la redirection de la sortie; STDOUT est la sortie par dØfaut. On aurait aussi bien pu Øcrire:

print STDOUT "Nombre lu : $nombre\n";

Ainsi STDIN est le nom de l’entrØe, STDOUT celui de la sortie et STDERR celui du fichier erreur.

STDIN, STDOUT, STDERR sont des manipulateurs de fichier, ou filehandles, qui existent en permanence dans une application Perl. Un filehandle est un nom que l’on donne un fichier, un pipe ou une socket afin de pouvoir y rØaliser facilement des entrØes/sorties. Pour crØer un filehandle et l’associer un fichier, on utilise la fonction open. Exemples:

open( MANIPULE, "NomDeMonFichier"); open( MANIPULE, "> nomfic");

open( MANIPULE, "| commande de sortie du pipe");

MANIPULE donne alors acc?s au fichier ou au pipe auquel il a ØtØ associØ jusqu’ ce que cette association soit fermØe ou que l’on effectue un nouvel open sur ce filehandle. STDIN, STDOUT, STDERR peuvent Œtre fermØs et rouverts.

1.1.2. Les variables

Dans notre premier exemple, nous n’avons donc pas eu dØclarer la variable $nombre. En effet, le symbole $ indique Perl que $nombre peut contenir une variable: un nombre ou une cha ne de caract?res. Nous appellerons cela une variable scalaire. Il y a d’autres variables:

VARIABLE

un filehandle

$VARIABLE

une variable scalaire

@VARIABLE

un tableau indexØ par des nombres

%VARIABLE

un tableau indexØ par des cha nes de caract?res

&VARIABLE

une subroutine

*VARIABLE

tout ce qui s’appelle VARIABLE

On peut affecter des variables, modifier leur valeur; exemples:

             $nombre = 4278;                  # un entier

$chaine = "coucou";    # une chaîne de caractères $commande = `who | grep toto`; # une commande

En Perl, un commentaire est prØcØdØ par #.

Une ligne d’instruction Perl se termine toujours par ; .

Si une variable n’est pas initialisØe par l’utilisateur, elle est automatiquement initialisØe la valeur nulle (0). Une variable est ØvaluØe comme un nombre, une cha ne, un boolØen ou un ØlØment de tableau en fonction du contexte. Perl effectue la conversion automatiquement. Ainsi:

$magic = "45"; print $magic+1, "\n";

Le rØsultat de l’exØcution de ce script est "46".

1.1.3. Comment lancer un script Perl?

Il y a plusieurs mani?res pour lancer votre premier script!

•  En ligne :

> perl  -e 'print "coucou \n" ; '

•  Si on utilise un fichier pour stocker le script:

> perl nomfic

•  Si votre syst?me supporte #!, vous pouvez spØcifier le nom de l interprØteur en mettant en tŒte du script l’incantation:

#!/usr/bin/perl

Le fichier contenant le script doit Œtre exØcutable (chmod u+x nomfic); pour exØcuter le script, on peut ensuite taper:

> nomfic

•  En dernier recours, on peut remplacer l’incantation ci-dessus par la ligne:

eval '/usr/bin/perl  -S  $0  ${ 1 + "$@" }'  if  0 ;

1.1.4. Une variable sympa : $_

La variable $_ est affectØe par un grand nombre d’opØrations.

Elle permet d accØder la ligne courante d’un fichier que l’on est en train de consulter (cf. $0 en awk).

1.1.5. Comment exprimer des conditions?

Perl dispose d’une boucle while dont le corps s’exØcute tant que la condition est vraie. Exemple:

!#/usr/bin/perl $credit = 10; while ($credit != 0)

{ print "J’offre un café à Rouv ! \n  ";

  $credit - = 2.5; } print " J’ai plus de sous! \n ";

La   condition $credit!=0 est  vraie  tant  que $credit ne  vaut  pas  0.   L opØrateur !=

(diffØrent) compare deux valeurs numØriques et retourne vrai si la premi?re est diffØrente de la seconde; sinon il retourne faux.

Perl n a pas de type boolØen; une valeur est vraie si elle est diffØrente de 0 ou "0" ou ’’’’ (cha ne vide). Les opØrateurs relationnels tels que ==, !=, <, retournent 1 pour vrai, 0 pour faux. D autres opØrateurs peuvent retourner d autres valeurs non nulles pour vrai et la cha ne vide pour faux.

Donc tout ce qui a une valeur peut Œtre utilisØ comme condition d un while; par exemple, une affectation, puisqu elle retourne la valeur finale de la variable affectØe:

!#/usr/bin/perl while ( $_ = <ARGV>)

{ print $_; }

Ce script permet de faire afficher les unes la suite des autres toutes les lignes des fichiers passØs en argument dans la ligne de commande. C est l Øquivalent de la commande shell cat.

ARGV est un filehandle; <ARGV> est l entrØe.

Si ce script est enregistrØ sous le nom equivcat et que toto, tutu et titi sont des fichiers, la ligne de commande:

> equivcat toto  tutu  titi

a pour rØsultat le stockage de la premi?re ligne de toto dans $_ et son impression sur la sortie standard. Puis la deuxi?me ligne de toto est rangØe dans $_ et affichØe. Et ainsi de suite jusqu Øpuisement de toto. L opØration est alors rØitØrØe avec tutu, puis avec titi.

Le script prØcØdent peut encore Œtre simplifiØ:

!#/usr/bin/perl while ( <>) { print ; }

On obtient le mŒme rØsultat que prØcØdemment. En effet, <ARGV> et <> reprØsentent la mŒme chose; de plus, un symbole dØsignant une entrØe, utilisØ seul dans une condition de boucle while, affecte automatiquement la variable $_; enfin, si l on ne prØcise pas de param?tre print, le contenu de $_ est affichØ par dØfaut.

L autre fa on d exprimer une condition en Perl est d utiliser if. L exemple suivant est l Øquivalent du grep du shell:

!#/usr/bin/perl

$pattern = shift( @ARGV ); while (<>) { if ( /$pattern/)

   { print ; }

}

Le premier argument passØ la commande est le pattern rechercher; il est stockØ dans la variable $pattern. Le reste des arguments est considØrØ comme des noms de fichiers; c est dans leur contenu que le pattern va Œtre recherchØ. Les lignes dans lesquelles $pattern a ØtØ reconnu sont ensuite affichØes.

Que se passe-t-il si la recherche est effectuØe dans une ligne vide?

Une ligne vide contient en fait le caract?re ’’\n’’, dont la valeur est vrai; elle n’est donc pas vraiment vide! On continue alors la recherche dans la ligne suivante. Toute ligne se termine d’ailleurs par ’’\n’’.

La fonction print n’effectue pas de retour la ligne automatique; on est donc obligØ de spØcifier si on le dØsire.

1.1.6. La vØritØ sur les tests

Les opØrateurs de test ne sont pas les mŒmes suivant que l’on compare des valeurs numØriques ou des cha nes de caract?res. Ces opØrateurs retournent 1 si la comparaison est vraie, 0 sinon.

OpØrateur de test sur les nombres

OpØrateur de test sur les cha nes

Signification

==

eq

Øgal

!=

ne

diffØrent

gt

supØrieur

>=

ge

supØrieur ou Øgal

lt

infØrieur

<=

le

infØrieur ou Øgal

<=>

cmp

diffØrent, avec retour du signe

Il faut donc faire attention quand on Øcrit un test; exemple:

$a = "5"; $b = "10";

if ( $a < $b )    { print " $a < $b \n";} if ( $a gt $b ) { print " $a gt $b \n";}

Le rØsultat de ce script est:

5 < 10             # comparaison numØrique

5 gt 10             # car la valeur ASCII de 1 est plus petite que celle de 5

1.1.7. Les opØrateurs scalaires

Voici une liste d opØrateurs, parmi les plus importants: • SØlection par les patterns

$a =? /pat/

matching; retourne vrai si $a contient le pattern pat

$a =? s/p/m/

substitution des p dans $a par des m

$a =? tr/a-z/A-Z/

OpØrateurs logiques

conversion des minuscules en majuscules

$a && $b

et logique

$a || $b

ou logique

! $a

OpØrateurs arithmØtiques

nØgation

$a + $b

addition

$a - $b

soustraction

$a * $b

multiplication

$a / $b

division

$a % $b

modulo

$a ** $b

$a exposant $b

++ $a, $a ++

incrØmentation

-- $a, $a --

dØcrØmentation

rand($a)

tire alØatoirement une valeur entre 0 et $a

OpØrateurs sur les cha nes de caract?res

$a . $b

concatØnation

 

$a x $b

$a rØpØtØe $b fois

 

substr( $a, $i, $l)

extraction d une sous cha ne de $a commen ant position $i et ayant pour longueur $l

la

index( $a, $b)

OpØrateurs pour l affectation

position de la cha ne $b dans $a

 

$a = $b

affectation

 

$a +=$b

addition et affectation

 

$a -=$b

soustraction et affectation

 

$a .=$b

OpØrations sur les fichiers

concatØnation et affectation

 

-r $a

retourne vrai si $a est autorisØ en lecture

 

-w $a

retourne vrai si $a est autorisØ en Øcriture

 

-d $a

retourne vrai si $a est un rØpertoire

 

-f $a

retourne vrai si $a est un fichier rØgulier

 

-T $a

retourne vrai si $a est un fichier texte

 

Les opØrateurs && et || sont des opØrateurs court-circuit. Cela signifie que si l Øvaluation de la partie gauche est suffisante pour dØcider de la valeur finale de l expression, la partie droite n est pas ØvaluØe.

Il y a bien sßr d autres opØrateurs, mais ceux-ci suffisent pour commencer!

1.1.8. ComplØments

Voici un exemple qui reprend ce que nous avons vu jusqu ici, plus quelques petites choses nouvelles:

#!/usr/bin/perl

open(FIND," find . -print |")||die"find n’a pas démarré:$!\ n";

FILE: while ( $nomfic = <FIND>) {  chop $nomfic;    next FILE unless -T $nomfic;    if ( ! open( FICTEXT, $nomfic ) )

   {  print STDERR  "Ouverture de $nomfic impossible ";        next FILE;

    } while ( <FICTEXT> )

   { foreach $mot ( @ARGV )

      { if ( index($_, $mot) >= 0)

         {  print $nomfic, " \n ";     next FILE;

         }

      }

    }

}

Le but de ce programme est de retrouver, dans les fichiers texte du rØpertoire courant, les arguments passØs lors de l appel du script.

La variable $! contient le message d erreur produit par le syst?me lors de l Øchec d ouverture du filehandle FIND.

Il est possible d’Øtiqueter une boucle; le label FILE permet next de faire appel de nouveau la boucle. L opØrateur next indique la boucle effectuer en spØcifiant son Øtiquette.

foreach est une structure de boucle puisqu elle permet $mot de prendre pour valeur les ØlØments de @ARGV, successivement.

La fonction index retourne la position de $mot dans la ligne courante s il a ØtØ trouvØ, -1 sinon.

1.2. LES LISTES

En plus des opØrateurs scalaires, Perl dispose de nombreux opØrateurs travaillant sur les listes. La force de Perl, c’est de pouvoir agir sur plusieurs objets en une seule ligne de commande.

1.2.1. Qu est-ce qu’une liste?

Une liste est tout simplement un ensemble ordonnØ de scalaires. On peut donc avoir des listes de nombres, de cha nes de caract?res, ou un mØlange des deux. Une liste portant un nom est appelØe tableau.

Comme une liste est ordonnØe, on peut donc parler de son premier ØlØment, de son deuxi?me ØlØment , et de son dernier ØlØment. Les ØlØments d’une liste sont donc accessibles sØparØment. Le premier ØlØment porte le numØro 0, le second le numØro 1, etc.

Lorsqu’on tape une commande Perl, ses arguments sont rangØs dans le tableau @ARGV. Donc

@ARGV[0] est le premier argument et

@ARGV[$#ARGV] est le dernier, sachant que $#ARGV donne acc?s la position du dernier ØlØment.

L’opØrateur range, notØ .. , produit une liste de valeurs comprises entre les valeurs des opØrandes gauche et droit. Par exemple, le script suivant permet de faire afficher tous les arguments de la commande faisant appel lui :

#!/usr/bin/perl foreach $i (0..$#ARGV) { print $ARGV[$i];    if ($i == $#ARGV)    { print "\n"; }    else

   { print " " ; }

}

L’opØrateur de construction d’une liste est la virgule, sØparateur des diffØrents ØlØments. Perl s’attend en gØnØral trouver une liste entre parenth?ses; par exemple :

@speinf =

('seb','cricri','pascal','xav','gilles','hugo','sissou');

@chiffre = ( 1, 2, 3, 4, 5, 6, 7, 8, 9 );

# même chose que ( 1..9 )

@etudiant = ( $no_etudiant, $nom, $prenom, $adresse );

Les parenth?ses sont nØcessaires ici; en effet, la virgule est moins prioritaire que l’affectation.

Une liste parenthØsØe de scalaires peut Œtre affectØe directement par une liste de valeurs, comme le montrent les exemples suivants :

( $no_compte, $debit, $credit ) = ( 14578963, 2000, 0 );

($nom,$passwd,$uid,$gid,$gcos,$home,$shell)=split(/:/,<PASSWD>); ( $tab[0], $tab[1], $tab[2], $tab[3] ) = @speinf;

split crØe une liste de cha nes de caract?res en scindant la ligne courante du fichier que PASSWD permet de manipuler, chaque occurrence des : . Le troisi?me exemple montre que l’on peut affecter une liste partir d’un tableau, quelque soit la taille de celui-ci. Si le tableau est trop grand, les derni?res valeurs ne sont pas prises en compte. S’il est trop petit, les valeurs non affectØes de la liste demeurent indØfinies.

La taille d’un tableau peut Œtre modifiØe: des ØlØments peuvent Œtre ajoutØs, supprimØs. La fonction splice permet de manipuler ainsi des tableaux. Sa syntaxe est :

splice ( ARRAY, INDEX, LONGUEUR [, LIST] )

ARRAY est le tableau auquel s’applique splice. INDEX est le premier ØlØment de ARRAY qui va dispara tre. LONGUEUR est le nombre d’ØlØments de ARRAY qui vont dispara tre. LIST est la liste Øventuelle dont les ØlØments seront insØrØs dans ARRAY partir de la position INDEX. Un exemple d’utilisation :

@arbre = ( 'sapin', 'épicéa', 'chêne', 'peuplier', 'hêtre' );

@modif = splice ( @arbre, 1, 3, 'boulot', 'palmier' );

Le rØsultat de cette fonction est une modification du tableau @arbre; on a maintenant :

@arbre = ( 'sapin', 'boulot', 'palmier', 'hêtre' ); splice retourne la liste des ØlØments de @arbre qu’elle a modifiØs :

@modif = ( 'épicéa', 'chêne', 'peuplier' );

Les fonctions suivantes sont utiles et simples pour travailler avec des listes:

$a = shift(@tab);

# $a contient le premier élément de @tab;

@tab a perdu cet élément

$b = pop(@tab);

# $a contient le dernier élément de @tab;

@tab a perdu cet élément

unshift(@tab, $a );

# insertion de $a en tête de @tab

push(@tab, $b );

# insertion de $b en fin de @tab

1.2.2. S’il vous pla t! On ne s’endort pas!

Il y a deux choses importantes   retenir sur les listes.

Premi?rement, il est important pour certains opØrateurs de savoir s’ils sont ØvaluØs comme un ØlØment d’une liste. Ils retournent alors l’intØrieur d’une liste des valeurs diffØrentes de celles qu’ils auraient retournØes ailleurs. Prenons l’exemple de l’opØrateur d’entrØe <> :

$a = <STDIN>;

# $a contient la ligne courante de l'entrée standard

@tab = <STDIN>;

# @tab contient toutes les lignes qu'il reste dans l'entrée standard

Deuxi?mement, une liste (la structure syntaxique) concat?ne toujours ses valeurs scalaires et ses tableaux, comme s’il s’agissait d’une seule et longue liste. Chaque ØlØment de la liste est ØvaluØ comme une expression dans un contexte de tableau, et s’il produit une liste, les valeurs de cette liste sont ajoutØes la liste de dØpart, comme s’elles avaient ØtØ spØcifiØes sØparØment. Un exemple, pour Øclaircir tout :

@a = ( 1 .. 3);

@b = (78,45,@a,92); # équivaut @b = (78,45,1,2,3,92)

             @a = ();              # liste vide

             @b = ( 0, @a, 4 );     # équivaut à @b = ( 0, 4 )

Comme @a est ØvaluØ dans un contexte de tableau, il renvoie la liste qu’il contient. S’il Øtait ØvaluØ dans un contexte scalaire, @a renverrait le nombre d’ØlØments qu’il comporte. Exemple:

 while (@a) # la boucle est effectuée autant de fois que @a contient d'éléments.

{ #code }

1.2.3. Quelques opØrateurs usuels sur les listes

On utilise le tableau suivant comme argument :

@speinf =

('seb','cricri','pascal','xav','gilles','hugo','sissou');

OpØrations                                         RØsultats

$speinf[2]                      ('pascal')

@speinf[3, 6]                   ('xav','sissou')

sort @speinf                     ('cricri','gilles','hugo','pascal',

 'seb','sissou' ,'xav')

reverse @speinf                 ('sissou','hugo','gilles','xav',

 'pascal', 'cricri', 'seb')

reverse sort @speinf            ('xav','sissou','seb','pascal','hugo',

 'gilles','cricri')

grep(/ill/, @speinf)            ('gilles')

3..7

( 3, 4, 5, 6, 7 )

reverse 3..7

( 7, 6, 5, 4, 3 )

@speinf[0..2]

('seb', 'cricri', 'pascal')

1.2.4. Et on fait quoi avec les listes?

Forts de tout ce que nous venons d’apprendre, nous allons passer un exemple plus pratique d’utilisation des listes. Imaginons qu’on veuille rØcupØrer les noms de tous les fichiers texte de notre compte.

Il suffit de faire appel au script suivant, gr ce    la ligne de commande:

> nom_du_script *

* donne les noms de tous les fichiers et rØpertoires du compte.

#!/usr/bin/perl while (@ARGV)

{ $fichier = shift @ARGV;    push(@fichier_texte, $fichier) if -T $fichier; } print join(' ', @fichier_texte), "\n";

Dans le while, @ARGV est ØvaluØ dans un contexte scalaire. Il retourne donc le nombre d’arguments passØs au script (ici, le nombre de fichiers et rØpertoires du compte). La variable $fichier re oit le premier ØlØment de la liste @ARGV. @ARGV perd cet ØlØment. Si

$fichier est effectivement un fichier texte (test avec -T), alors il est rangØ       la fin de la liste @fichier_texte.

La fonction join permet ensuite de constituer une cha ne de caract?res oø les ØlØments de @fichier_texte sont sØparØs par un espace.

Autre possibilitØ :

#!/usr/bin/perl

print join(' ', grep(-T, @ARGV)), "\n";

La fonction grep de Perl est plus puissante que la fonction d’Unix. En effet, elle accepte non seulement les expressions rØguli?res comme crit?re, mais aussi les expressions Perl.

Si on avait voulu la liste des fichiers texte classØs par ordre alphabØtique, on aurait Øcrit :

#!/usr/bin/perl print join(' ', sort grep(-T, @ARGV)), "\n";

1.3. L'INTERPOLATION DE VARIABLE

ConsidØrons les lignes de code suivantes :

print "$var \n"; print "@ARGV \n";

Ces commandes interpolent respectivement le scalaire $var et le tableau @ARGV en une cha ne de caract?res (par dØfaut, les ØlØments de @ARGV seront sØparØs par un espace).

Attention, l’interpolation de variable n’a pas lieu entre quotes simples. Pour mieux comprendre, prenons un exemple; soit le script afficharg, auquel on passe les arguments suivants:

> afficharg pascal gilles xav

Si dans afficharg on utilise les commandes suivantes, on obtient les rØsultats suivants:

print "@ARGV";

pascal gilles xav

print @ARGV;

pascalgillesxav

print '@ARGV\n';

@ARGV\n

L’interpolation de variable est Øgalement exØcutØe l’intØrieur de backquotes, mais elle s’accompagne de l’exØcution de la cha ne contenue dans les backquotes comme d’une commande dont le rØsultat peut Œtre affectØ:

$lignes = `wc -l $nomfic`;

Si les caract?res suivant le nom d’une variable interpoler peuvent prŒter confusion, il faut dØlimiter ce nom avec des accolades; exemple:

$fred = "pay"; $fredday = "wrong!";

             $barney = "It's $fredday";                  # "It's wrong!"

             $barney = "It's ${fred}day";                # "It's payday"

1.4. LA SELECTION PAR LES PATTERNS : LE MATCHING

Perl dispose de deux opØrateurs de sØlection par les patterns:

•  //, opØrateur de sØlection; il recherche le pattern entre // dans une cha ne de caract?res et retourne vrai ou faux suivant que le pattern a ØtØ trouvØ ou non.

•  s///, opØrateur de substitution; il fait la mŒme chose, mais, en plus, remplace la partie matchØe de la cha ne par ce qui se trouve entre les deux derniers dØlimiteurs.

Les patterns sont spØcifiØs en utilisant les expressions rØguli?res. En voici quelques exemples:

.

matche n’importe quel caract?re sauf newline

[a-z0-9]

matche un caract?re de cet ensemble

[^a-z0-9]

matche tout caract?re ne figurant pas dans cet ensemble

\d | \D

matche un chiffre | matche tout sauf un chiffre

\w | \W

matche un caract?re alphanumØrique | contraire

\s | \S

matche un caract?re d’espacement | contraire

\n | \r | \t | \f | \b

matchent respectivement newline, return, tab, formfeed, backspace ( l’intØrieur de crochets seulement)

\0 | \000

matchent le caract?re nul

\nnn

matche le caract?re ASCII ayant cette valeur octale

\metachar

matche le caract?re lui-mŒme (\| , \. , \*, )

(abc)

enregistre la sØlection

\1

matche le premier pattern contenu dans la sØlection

\2 | \3

matche le deuxi?me | troisi?me pattern contenu dans la sØlection

x?

matche 0 ou 1 x oø x est un des motifs ci-dessus

x*

matche 0 ou plusieurs x

x+

matche 1 ou plusieurs x

x{m, n}

matche au moins m x et au plus n

abc

matche tous les a, b, c

ok | coucou | he

matche ok ou coucou ou he

\b | \B

matche un dØlimiteur de mots | contraire

^

donne acc?s au dØbut de ligne ou de cha ne

$

donne acc?s   la fin de ligne ou de cha ne

Lorsque l’on fait de la sØlection par pattern, il y a Øgalement des variables magiques qui sont affectØes lorsque le matching rØussit:

•  $&, contient le pattern recherchØ

•  $‘, contient tout ce qu’il y a avant la sØlection

•  $’, contient tout ce qu’il y a apr?s la sØlection

•  $1, $2, , $9 contiennent les patterns matchØs

Un exemple de matching en Perl; imaginons que l’on dispose d’un fichier dont la ligne courante (contenue dans $_) est :

Date : 3 juin 1995 13:26:00 GMT

Cette ligne peut Œtre dØcomposØe comme suit:

/^Date : (\d+)(\w+)(\d+)(\d+):(\d+):(\d+)(.*)$/;

$jour = $1;

# récupère "3"

$mois = $2;

# récupère "juin"

$annee = $3;

# récupère "1995"

$heure = $4;

# récupère "13"

$minute = $5;

# récupère "26"

$seconde = $6;

# récupère "00"

$reference = $7;

# récupère "GMT"

Si on avait fait les regroupements suivants:

/^Date : ((\d+)(\w+)(\d+))((\d+):(\d+):(\d+))(.*)$/

on aurait la dØcomposition:

$date = $1;

$jour = $2;

$mois = $3;

$annee = $4;

# récupère "3 juin 1995"

$temps = $5;

$heure = $6;

$minute = $7;

$seconde = $8;

$reference = $9;

# récupère "13:26:00"

1.5. LES TABLEAUX ASSOCIATIFS

On peut dire que c’est la partie la plus importante de cette prØsentation de Perl, puisque c’est la propriØtØ principale de ce langage. Les tableaux associatifs permettent de mettre en place des structures rØcursives telles que les arbres.

Un tableau associatif est une liste constituØe de paires de valeurs indexØes par la premi?re valeur de chaque paire, appelØe clØ. Les clØs sont rangØes dans une table de hachage, ce qui permet de consulter rapidement le tableau auquel elles sont associØes, quelque soit sa taille.

Un tableau associatif est dØclarØ par le symbole %. Exemple:

%caracteristiques= ( 'xav', 'discret',

'cricri', 'marrant', 'seb', 'râleur',

'gilles', 'emporté',

'pascal', 'cultivé',

'hugo', 'délire', 'sissou', 'bavarde' );

On utilise donc la mŒme notation que pour les tableaux simples.

Lors de l’Øvaluation de %caracteristiques dans un contexte de tableau, on n’obtiendra pas forcØment les paires dans cet ordre (cela dØpend de la fonction de hachage).

Pour accØder un ØlØment d’un tableau associatif, on utilise les accolades et la clØ:

$caract = $caracteristiques{'xav'};    # $caract prend la valeur 'discret'

$home = $ENV{'HOME'};

$SIG{'UP'} = 'IGNORE';

Les deux derniers tableaux associatifs citØs font rØfØrence deux tableaux propres            Perl: • %ENV permet de consulter et fixer les variables d’environnement de l’utilisateur;

• %SIG permet de fixer les valeurs des signaux syst?me.

Les tableaux associatifs permettent de lier un ensemble de cha nes un autre ensemble de cha nes. Ainsi, ils se rapprochent des pointeurs disponibles dans les autres langages.

La fonction keys permet d’accØder la liste des clØs d’un tableau associatif. Cette fonction est souvent utilisØe comme suit:

foreach $key ( sort keys( %tab_nom ) )

{ }

Les tableaux associatifs sont des structures puissantes qui permettent des consultations rapides et qui nØcessitent peu de code.

2 . PERL EN DETAIL


 

2.1. LES VARIABLES SCALAIRES

Nous avons vu plus haut que pour Perl les variables scalaires sont des nombres ou des cha nes de caract?res. Des opØrateurs permettent de les manipuler: elles peuvent Œtre affectØes, lues et Øcrites dans des fichiers.

2.1.1. Les nombres

Une variable scalaire peut contenir un entier ou un dØcimal. De toute fa on, Perl utilise la mŒme reprØsentation pour les deux: flottant double prØcision (l Øquivalent de double en C).

Un littØral est la fa on dont une valeur est reprØsentØe dans le texte d un programme Perl. Perl accepte tous les littØraux flottants disponibles en C. Exemples:

1.435 +3.78

-23e-4

45.7E7

Les littØraux entiers sont reprØsentØs simplement par:

45

-67

Ils ne doivent pas commencer par 0; en effet, Perl reconna t les littØraux octaux et hexadØcimaux, dont les reprØsentations commencent respectivement par 0 et 0x ou 0X. Les chiffres hexadØcimaux A F reprØsentent les valeurs 10 15. Exemples:

             0377        # 377 octal, équivaut à 255 en décimal

             -0xff       # -FF hexadécimal, équivaut à 255 en décimal

2.1.2. Les cha nes de caract?res

Ce sont des suites de caract?res pris dans l ensemble des 256 caract?res codØs sur 8 bits. La plus petite cha ne est la cha ne nulle; la plus longue remplirait toute la mØmoire disponible. Comme les nombres, les cha nes ont une reprØsentation littØrale; il y en a deux en fait: entre simples quotes et entre doubles quotes.

•  Les simples quotes ne font pas partie de la cha ne de caract?res qu elles encadrent; elles sont l pour indiquer Perl le dØbut et la fin de la cha ne. Une cha ne entre simples quotes peut contenir n importe quel caract?re; il y a cependant deux exceptions: pour avoir une simple quote ou un antislash dans une cha ne entre simples quotes, ceux-ci doivent Œtre prØcØdØs par un antislash. Exemples:

                'coucou'             # 6 caractères: c, o, u, c, o, u

'c\'est pas gagné! ' # c’est pas gagné

                'A bientôt \n'       # A bientôt \n

\n entre simples quotes n est pas interprØtØ comme un retour la ligne mais comme deux caract?res, \ et n.

•  Une cha ne entre doubles quotes est l Øquivalent d une cha ne de caract?res en C. L antislash permet donc de spØcifier certains caract?res de contr le ou tout caract?re par ses reprØsentations octale et hexadØcimale. Exemples:

"coucou \n"     # coucou, un espace et un retour à la ligne "nouveau \177" # nouveau , un espace et le caractère delete

Un antislash peut prØcØder de nombreux caract?res pour signifier diffØrentes choses, comme le montre la table suivante:

      \n                         newline

      \r                         return

      \t                          tab

      \f                          formfeed

      \b                         backspace

      \v                         vertical tab

      \a                         bell

      \e                         escape

      \007                      n importe quelle valeur octale ASCII (ici, 007=bell)

      \x7f                      n importe quelle valeur hexadØcimale ASCII (ici, 7f=delete)

      \cC                       n importe quel caract?re de contr le (ici, control C)

      \\                          antislash

      \l                         mettre la lettre suivante en minuscule

       \L                        mettre toutes les lettres suivantes en minuscule, jusqu  \E

      \u                        mettre la lettre suivante en majuscule

      \U                       mettre toutes les lettre suivantes en majuscule, jusqu   \E

\E    permet d achever \L et \U \"  double quote

A l intØrieur des doubles quotes, l interpolation de variable peut avoir lieu, comme nous l avons annoncØ au paragraphe 1.3. Pour empŒcher la substitution, on peut utiliser les simples quotes ou faire prØcØder le caract?re $ par un antislash; exemple:

$a = "Seb";

$b = "Salut " . '$a';     # $b contient "Salut $a" $b = "Salut \$a";     # idem

2.1.3. Les opØrateurs

Une liste d opØrateurs sur les variables scalaires est disponible au paragraphe 1.1.7. Perl dispose des opØrateurs arithmØtiques que l on trouve gØnØralement dans des langages tels que le C. Mais il poss?de Øgalement l’opØrateur d’exponentiation ** :

             3 ** 7      # 3 à la puissance 7

On trouve aussi des opØrateurs sur les cha nes de caract?res:

•  l opØrateur . , qui permet la concatØnation de deux cha nes; exemple:

             "hello " . "world";   # équivaut à "hello word"

•  les opØrateurs de comparaison de cha nes de caract?res; ils sont ØnumØrØs dans le chapitre

1.1.6.

•  l’opØrateur x, qui permet de rØpØter une cha ne autant de fois que l’indique la valeur de l’opØrande droit; exemple:

             "coucou" x 4          # équivaut à "coucoucoucoucoucoucoucou"

             "eh" x (3+1)          # équivaut à "eh" x 4, soit "eheheheh"

Les  parenth?ses     permettent      l’Øvaluation    de        l’expression     qu’elles            renferment,       avant l’exØcution de la rØpØtition. La partie enti?re de l’opØrande droit est calculØe et utilisØe pour la rØpØtition.

La multiplication et la division sont prioritaires par rapport            l’addition et la soustraction.

L’usage de parenth?ses permet de modifier les prioritØs.

Si une cha ne est utilisØe comme opØrande d’un opØrateur numØrique, Perl effectue automatiquement la conversion, de mŒme si une valeur numØrique a ØtØ utilisØe l oø une cha ne Øtait attendue.

Pour donner une valeur  une variable, on utilise l’affectation:

$a = 3;

$b = $b * 2;

Une affectation scalaire a une valeur; cette valeur est le nombre affectØ: $a = 3 a pour valeur 3. C’est pratique pour copier la mŒme valeur dans plusieurs variables:

$b = 4 + ($a = 3);     # $a contient 3 et $b contient 7 $c = $d = 5;    # $c et $d contiennent 5

Perl dispose d’opØrateurs d’affectation binaires:

$a += 3;

 Øquivaut

$a = $a + 3 ;

$b *= $a;

 Øquivaut

     $b = $b * $a ;

$str .= " ";

 Øquivaut

     $str = $str . " ";

Perl dispose aussi de l’auto-incrØmentation et de l’auto-dØcrØmentation, qui peuvent Œtre utilisØes sous forme de prØfixe ou de suffixe:

++$a;

$d = $c = 17;

 Øquivaut                   $a += 1;

$e = ++ $d;

# $d et $e valent tous les deux 18

$e = $c --;

# $e vaut 17 et $c vaut 16

2.1.4. Les noms de variables scalaires

Le nom d’une variable est constant tout au long d’un programme alors que la valeur qu’elle contient varie.

Les noms de variables scalaires commencent par $, peuvent contenir des lettres, des chiffres ou des underscores et Œtre aussi longs qu’on veut. Une diffØrence est faite entre minuscule et majuscule: $A et $a ne font pas rØfØrence la mŒme variable.

2.1.5. L’opØrateur chop()

Cet opØrateur prend comme unique param?tre le nom d’une variable, retire le dernier caract?re de la cha ne laquelle cette variable est Øgale ou Øquivalente et retourne le caract?re ØliminØ. Exemple:

$var = "bonjour a tous";

$lettre = chop($var);

# $var contient maintenant "bonjour a tou"; $lettre contient "s"

2.1.6. La variable scalaire <STDIN>

Lorsque <STDIN> est utilisØe l oø une valeur scalaire est attendue, Perl lit la ligne courante de l’entrØe standard (jusqu’au prochain newline) et utilise cette cha ne pour donner une valeur  <STDIN>. S’il n’y a rien lire, le programme Perl s’arrŒte et attend qu’une valeur soit saisie.

La valeur cha ne de <STDIN> se termine donc par un \n. L’opØrateur chop()permet de l’Øliminer. Un exemple d’utilisation:

print "Donnez un nombre :";

$a = <STDIN>; chop($a);

print "Votre nombre : $a";

2.1.7. L’opØrateur de sortie print()

L’opØrateur print permet d’obtenir sur la sortie standard (par dØfaut) la valeur scalaire du param?tre qu’on lui passe; exemple:

print "coucou"; # coucou s'affiche à l'écran

2.1.8. La valeur undef

Si une variable est utilisØe avant d’avoir ØtØ initialisØe, ce n’est pas grave; les variables non initialisØes ont pour valeur undef, qui est un 0 quand on parle de nombres ou la cha ne vide quand on parle de cha nes de caract?res. De nombreux opØrateurs retournent la valeur undef lorsque les param?tres qu’on leur a passØ n’ont pas de sens.

<STDIN> retourne normalement la ligne courante de l’entrØe; s’il n’y a rien lire, il retourne undef.

2.2. LES LISTES ET LES TABLEAUX

Un tableau est une liste ordonnØe de scalaires. Le nombre d ØlØments d un tableau est illimitØ. Le plus petit tableau n a pas d ØlØment; le plus grand remplirait toute la mØmoire disponible.

2.2.1. ReprØsentation littØrale

Un tableau est donc un ensemble de scalaires sØparØs par des virgules et encadrØ par des parenth?ses. Ces ØlØments ne sont pas forcØment des constantes: ils peuvent Œtre des expressions qui seront ØvaluØes chaque utilisation. Exemples de tableaux:

( 1, 2, 3 )

("coucou", 4.5 )

             ()               # tableau vide

Il existe Øgalement un opØrateur de construction de liste: range, notØ .. . Il permet de crØer une liste dont les valeurs sont comprises entre l opØrande gauche et l opØrande droit et sont obtenues partir de l opØrande gauche par incrØmentations successives de pas 1; exemples:

             ( 1..3 )         # équivaut à la liste (1, 2, 3 )

             ( 3.3 .. 6.1 )   # équivaut à la liste ( 3.3, 4.3, 5.3 )

2.2.2. Les variables tableaux

Un nom de tableau vØrifie les mŒmes propriØtØs qu un nom de scalaire, si ce n est qu il commence par le caract?re @ . La valeur d un tableau qui n a pas encore ØtØ initialisØ est la liste vide (). Exemples:

@tableau

             @Tableau         # différent de @tableau

@un_tableau

2.2.3. L affectation

Elle permet de donner une valeur  une variable tableau; exemples:

@tab = ( 1, 2, 3 );

@chiffres = 6;

Dans ce deuxi?me exemple, le scalaire 6 devient l unique ØlØment du tableau @chiffres. Le nom d un tableau peut appara tre l intØrieur d une liste. Perl le remplace alors automatiquement par ses ØlØments; exemple:

             @chiffres = ( @tab, 6 );    # équivaut à @chiffres = (1,2,3,6)

Si un tableau contient uniquement des rØfØrences des variables, il peut Œtre traitØ comme une variable. En particulier, il peut constituer la partie gauche d’une affectation; exemples:

( $a, $b, $c ) = ( 1, 2, 3 );

# $a contient 1, $b 2, $c 3

( $d, @tab ) = ( $a, $b, $c );

# $d a la même valeur que $a,

@tab contient( $b, $c )

Si le nombre d’ØlØments affectØs ne correspond pas au nombre de variables, les valeurs en trop ( droite de l’affectation) sont ØliminØes et les variables non affectØes ( gauche de l’affectation) re oivent la valeur undef.

Si une variable scalaire est affectØe par un tableau, elle re oit en fait le nombre d’ØlØments de ce tableau; exemples:

@tab = ( 1, 2, 3 );

             $a = @tab;       # $a contient la valeur 3

             ($a) = @tab;     # $a contient le premier élément de @tab : 1

Le troisi?me exemple est une affectation entre tableaux, alors que le deuxi?me est une affectation entre scalaires. La valeur d’une affectation entre tableaux est un tableau, ce qui permet d’affecter des tableaux en cascade; exemples:

@tab = ( @chiffres = ( 1, 2, 3 ) );

# @tab et @chiffres contiennent tous les deux ( 1, 2, 3 )

             @tab = @chiffres = ( 1, 2, 3 );       # même chose

2.2.4. L’acc?s aux ØlØments

Les ØlØments d’un tableau sont repØrØs par des entiers; le premier ØlØment est indexØ par 0. Ils sont accØdØs par des variables scalaires ou des tableaux; exemples:

@tab = ( 1, 2, 3 );

 

$a = $tab[0];

# $a contient le premier élément de @tab, soit 1

$b = $tab[ $a ];

# $b contient le deuxième élément de

@tab, soit 2

@tab2 = @tab[0, 2];

# @tab2 contient le premier et le dernier élément de @tab, soit( 1, 3 )

Dans le dernier exemple, on acc?de

une liste d’ØlØments du mŒme tableau et on crØe donc un

tableau, d’oø le signe @.

Si on tente d’accØder un ØlØment dont l’indice est supØrieur au nombre d’ØlØments du tableau, la valeur undef est retournØe; exemple:

@tab = ( 1, 2, 3 );

             $val = $tab[7];       # $val contient undef

Si on affecte un ØlØment dont l’indice est supØrieur au nombre d’ØlØments du tableau, celui-ci est Øtendu automatiquement, et les valeurs non affectØes re oivent la valeur undef; exemple:

@tab = ( 1, 2, 3 );

$tab[5] = 6;

# @tab contient maintenant ( 1, 2, 3, undef, undef, 6 )

Enfin, la variable $#tab permet d’accØder l’indice du dernier ØlØment du tableau @tab.

2.2.5. Les opØrateurs push() et pop()

push permet d’ajouter un ØlØment ou une liste d’ØlØments           la fin d’un tableau. pop permet d’Øliminer le dernier ØlØment d’un tableau; exemples:

push ( @tab, $a );     # @tab = (@tab, $a) push ( @tab, 4, 5, 6 );    # @tab = (@tab, 4, 5, 6)

             $b = pop ( @tab );          # @tab = (1, 2, 3, 4, 5) et $b = 6

pop() renvoie la valeur undef si la liste qu’on lui a passØe en param?tre est vide.

2.2.6. Les opØrateurs shift() et unshift()

shift permet d Øliminer le premier ØlØment d un tableau. unshift permet d ajouter un ØlØment ou une liste d ØlØments en dØbut de tableau; exemples:

@tab = ( 1, 2, 3 ); unshift ( @tab, $a );    # @tab = ( $a, @tab ) unshift ( @tab, 4, 5, $c ); # @tab = ( 4, 5, $c, @tab )

             $b = shift ( @tab );        # @tab = (5,$c,1,2,3) et $b = 4

shift() renvoie la valeur undef si la liste qu’on lui a passØe en param?tre est vide.

2.2.7. L opØrateur reverse()

Cet opØrateur permet d inverser l ordre des ØlØments d un tableau. Il retourne une liste; exemples:

@tab = ( 1, 2, 3 );

@inv_tab = reverse ( @tab ); # @inv_tab = ( 3, 2, 1 ) @b = reverse ( @b ); # inverse @b et le range dans @b

2.2.8. L opØrateur sort()

Cet opØrateur permet de classer dans l ordre croissant des caract?res ASCII les ØlØments du tableau qu on lui passe en argument; exemples:

@x = sort ("petit", "moyen", "grand" );

# @x=("grand","moyen","petit")

@y = ( 1, 2, 4, 8, 16, 32, 64 );

             @y = sort (@y);             # @y = ( 1, 16, 2, 32, 4, 64, 8 )

2.2.9. L opØrateur chop()

Il fonctionne comme sur les variables scalaires: chaque ØlØment du tableau qu on lui passe en param?tre est amputØ de son dernier caract?re; exemple:

@machin = ("Coucou \n", "Ca va ? \n" );

             chop ( @machin );     # @machin = ("Coucou", "Ca va ?" )

2.2.10. Le tableau <STDIN>

Dans un contexte de tableau, cet opØrateur renvoie une valeur diffØrente que dans un contexte scalaire. En effet, il retourne une liste dont les ØlØments sont toutes les lignes restantes de l entrØe standard partir de la ligne courante, prises sØparØment. Les newline sont pris en compte.

2.2.11. Interpolation de tableaux

Les tableaux et leurs ØlØments peuvent eux aussi Œtre interpolØs l intØrieur des doubles quotes; exemples:

@speinf = ("seb", "cricri", "hugo");

$phrase1 = "$speinf[0] joue bien au baby."

# $phrase1 = "seb joue bien au baby"

$phrase11 = "$speinf[0, 1] jouent bien au baby."

# $phrase1 = "seb cricri jouent bien au baby"

$phrase2 = "@speinf s’occupent du 486."

# $phrase2 = "seb cricri hugo s’occupent du 386"

$speinf = "coucou";

$phrase3 = "voici $speinf[1]";       # $phrase3 = "voici cricri"

$phrase4 = "voici $speinf \[1]"; # $phrase4 = "voici coucou [1]" $phrase5 = "voici $speinf" . "[1]"; # $phrase5 = "voici coucou [1]" $phrase6 = "voici ${speinf }[1]"; # $phrase6 = "voici coucou [1]"

Les exemples des phrases 11 et 2 montrent que les ØlØments d une liste sont interpolØs dans l ordre et sØparØs par un espace. Les exemples des phrases 4, 5 et 6 montrent comment faire suivre une variable scalaire d un crochet ouvrant, sans que Perl interpr?te cela comme l interpolation d un ØlØment de tableau.


 

2.3. STRUCTURES DE CONTROLE

2.3.1. Les blocs d instructions

Un bloc d instructions est de la forme:

{ instruction 1;     instruction 2;

     dernière instruction;

}

C est donc une sØquence d instructions sØparØes par des points virgules, et encadrØe par des accolades. Perl exØcute les instructions dans l ordre.

2.3.2. L instruction if / unless

Une instruction if est de la forme:

if (expression)

{ instructions à exécuter si l’expression est vraie;

} else

{ instructions à exécuter si l’expression est fausse; }

Les accolades sont obligatoires!

L expression est ØvaluØe en tant que cha ne l exØcution. Si elle est Øgale la cha ne vide (de longueur 0) ou au caract?re "0", elle est ØvaluØe faux. Sinon elle est ØvaluØe vrai.

Le bloc else est optionnel.

Un exemple d instruction if:

print "Donnez votre age : \n";

$age = <STDIN>; chop ( $age ); if ($age >= 18)

{ print "Vous pouvez aller voter! "; } else

{ print "Vous êtes trop jeune pour voter! "; }

if peut Œtre remplacØ par unless. Cela revient dire: « Si l expression est fausse, alors ». unless peut avoir lui aussi un bloc else.

S il y a plus de deux choix possibles, on peut ajouter des blocs elsif une instruction if; exemple:

if (expression1) { bloc1; } elsif (expression2) { bloc2; } elsif (expression3) { bloc3; } else

{ bloc4; }

Le nombre de blocs elsif n est pas limitØ. Perl Øvalue les expressions les unes apr?s les autres; lorsqu il en rencontre une ayant pour valeur vrai, le bloc d instructions correspondant est exØcutØ et les autres sont ignorØs. Si toutes les expressions sont fausses, le else est exØcutØ (s il y en a un).

2.3.3. L instruction while / until

L instruction while permet de rØpØter l exØcution d un bloc d instructions tant que l expression de contr le est vraie; cette instruction est de la forme:

while (expression) { instruction_1;    instruction_2;

    instruction_n;

}

Pour exØcuter le while, Perl Øvalue l expression. Si elle est vraie, le bloc d instructions est exØcutØ. L expression est alors rØØvaluØe. Ceci se rØp?te jusqu ce que l expression soit fausse; le bloc d instructions est alors ignorØ.

while peut Œtre remplacØ par until; cela revient dire: « Tant que cette expression est fausse, exØcuter »; exemple:

until (expression)

{ bloc d’instructions; }

2.3.4. L instruction for

Elle est tr?s semblable   celle dont on dispose en C; elle est en effet de la forme:

for (initial_exp; test_exp; increment_exp)

{ instruction_1;    instruction_2;

    instruction_n;

}

Cela se traduit avec les instructions ØtudiØes jusqu ici par:

initial_exp; while ( test_exp ) { instruction_1;    instruction_2;

instruction_n;    increment_exp;

}

L initial_exp est ØvaluØe en premier; en gØnØral elle permet d initialiser un compteur de boucle (mais ce n est pas obligatoire). Ensuite la test_exp est ØvaluØe; si elle est vraie, le corps de boucle et l increment_exp sont exØcutØs. Perl rØØvalue alors test_exp , tant que cela est nØcessaire.

L exemple suivant permet de faire afficher les nombres de 1  10, sØparØs par un espace:

for ( $i = 1; $i <= 10 ; $i ++ )

{ print "$i"; }

2.3.5. L instruction foreach

Cette instruction affecte une variable scalaire avec les ØlØments d une liste pris les uns apr?s les autres et exØcute le bloc d instructions; elle est de la forme:

foreach $i ( @liste )

{ instruction_1;

    instruction_n;

}

La variable scalaire est locale la boucle; c est- -dire qu elle reprend la valeur qu elle avait avant l exØcution de la boucle lorsqu on sort de celle-ci.

On peut omettre le nom de la variable scalaire; dans ce cas $_ est utilisØe par dØfaut.

Si la liste qu on utilise est en fait simplement un tableau, alors la variable scalaire devient une rØfØrence chaque ØlØment de ce tableau, plut t que d Œtre une copie de chacun d eux. Cela signifie que si la variable scalaire est modifiØe, alors l ØlØment du tableau qu elle reprØsente alors est aussi modifiØ; un exemple pour y voir plus clair:

@val = ( 2, 5, 9 ); foreach $chiffre (@val)

{ $chiffre *= 3;}

# on a maintenant @val = ( 6, 15, 27 )

2.4. LES TABLEAUX ASSOCIATIFS

2.4.1. Les variables tableaux associatifs

Leur dØfinition est donnØe au paragraphe 1.5.

Leur nom commence par le symbole %. Il suit ensuite les mŒmes r?gles que les noms de variables scalaires ou de tableaux.

En gØnØral, on ne fait pas rØfØrence un tableau associatif dans son entier, mais ses ØlØments. Chaque ØlØment est accØdØ par sa clØ; ainsi, les ØlØments du tableau associatif %tab sont accØdØs par $tab{$cle}, oø $cle est une expression scalaire. Vouloir accØder un ØlØment du tableau qui n existe pas a pour rØsultat undef.

De nouveaux ØlØments sont crØØs par affectation et peuvent Œtre manipulØs comme des variables scalaires; exemples:

$tab{"coucou"} = "ca va? ";

# création de la clé "coucou", à laquelle est associée la valeur

"ca va? "

$tab{123.5} = 4568;

# création de la clé 123.5, à laquelle est associée la valeur

4568

             print "$tab{"coucou"}";          # affichage de "ca va? "

$tab{123.5} +=3;

# la valeur associée à la clé 123.5 est maintenant 4571

La reprØsentation littØrale d un tableau associatif est une liste de paires de clØs et des valeurs qui leur sont associØes. L ordre des paires dans la liste ne peut pas Œtre contr lØ; il dØpend de la fonction de hachage utilisØe par Perl pour accØder rapidement aux ØlØments du tableau; exemples:

%autre_tab = %tab;

# %autre_tab a les mêmes éléments que %tab

@liste = %tab;

# @liste = ("coucou", "ca va? ", 123.5, 4571)

2.4.2. Les opØrateurs sur les tableaux associatifs

L opØrateur keys()

Cet opØrateur retourne la liste des clØs du tableau associatif qu on lui passe en param?tre. L ordre des ØlØments de cette liste dØpend de la fonction de hachage utilisØe par Perl pour accØder rapidement aux ØlØments du tableau.

Les parenth?ses sont optionnelles. Exemples:

$tab{"coucou"} = "ca va? ";

$tab{123.5} = 4568;

@liste = keys(%tab);

# @liste = ("coucou ", 123.5) ou bien (123.5, "coucou")

                   @liste = keys %tab;       # idem

Les ØlØments des tableaux associatifs sont interpolØs    l intØrieur des doubles quotes; exemple:

foreach $key (keys %tab)

{ print "la valeur associée à la clé $key est $tab{$key}."; }

Dans un contexte scalaire, keys() retourne le nombre de paires (clØ-valeur) du tableau passØ en param?tre; exemple:

while ($i < keys %tab)

{ }

•  L opØrateur values()

Cet opØrateur retourne la liste des valeurs du tableau associatif qu on lui passe en param?tre, dans le mŒme ordre que les clØs retournØes par keys(). Les parenth?ses sont optionnelles. Exemple:

@liste_valeurs = values(%tab);

# @liste_valeurs contient("ca va?",4568)ou bien(4568,"ca va?")

•  L opØrateur each()

Pour examiner tous les ØlØments d un tableau associatif, on peut donc faire appel keys() puis rØcupØrer les valeurs correspondant aux clØs. En utilisant each(), on obtient directement une paire (clØ-valeur) du tableau passØ en param?tre.

A chaque Øvaluation de cet opØrateur pour un mŒme tableau, la paire suivante est retournØe, jusqu ce qu il n y ait plus de paire accØder; each() retourne alors la cha ne vide. L exemple prØcØdent peut alors s Øcrire:

while ( ($cle, $valeur) = each(%tab) )

{ print "la valeur associée à la clé $cle est $valeur . "; }

•  L opØrateur delete

Il permet d Øliminer la paire (clØ-valeur) du tableau associatif dont on a passØ la clØ en param?tre; exemple:

%tab = ("coucou ", "ca va? ", 123.5, 4571);

@element = delete $tab{"coucou"};

# @element = ("coucou", "ca va?") et %tab = (123.5, 4571)


 

2.5. LES ENTREES/SORTIES

2.5.1. Les entrØes avec STDIN

Lire l entrØe standard avec le manipulateur de fichier STDIN est tr?s simple. Nous l avons dØj fait avec l opØrateur <STDIN> qui peut Œtre ØvaluØ:

•  dans un contexte scalaire, la ligne courante de l entrØe standard ou undef si il n y a plus de ligne;

•  dans un contexte de tableau, au reste des lignes contenues dans l entrØe standard, sous forme de liste, chaque ligne Øtant un ØlØment de la liste.

Pour lire les lignes contenues dans l entrØe standard et les manipuler sØparØment, on utilise $_ comme suit:

while ($_ = <STDIN>)

{ # code }

Tant qu il y a quelque chose lire <STDIN> est ØvaluØ vrai et la boucle s exØcute. Quand il n y a plus rien lire, <STDIN> retourne undef, qui est ØvaluØ faux, ce qui termine la boucle. Quand un test de boucle consiste uniquement en un opØrateur d entrØe (comme < >), Perl copie automatiquement la ligne lue dans $_; donc, l exemple prØcØdent peut s Øcrire:

while (<STDIN>)

{ # code }

2.5.2. Les entrØes avec l opØrateur diamant <>

Cet opØrateur se comporte comme <STDIN>:

• dans un contexte scalaire, il retourne une ligne ou undef;

dans un contexte de tableau, il retourne les lignes restantes.

Cependant, il lit les donnØes dans les fichiers spØcifiØs dans la ligne de commande faisant appel au programme Perl. Par exemple, le script suivant:

#!/usr/bin/perl while (<>) { print; }

a le mŒme rØsultat que la commande cat; s il est stockØ dans le fichier pcat et qu on fait appel lui avec la ligne de commande:

> pcat fic1 fic2 fic3

les contenus des trois fichiers seront affichØs  la suite les uns des autres.

En fait, <> fonctionne gr ce au tableau @ARGV dont nous avons dØj        fait la connaissance au chapitre 1. Pour ceux qui n ont pas suivi, ce tableau est la liste des arguments de la ligne de commande.

2.5.3. La sortie avec STDOUT

Perl utilise print et printf pour Øcrire sur la sortie standard.

• print

Cet opØrateur prend une liste de cha nes et les envoie les unes apr?s les autres sur la sortie standard. print retourne une valeur, comme tout opØrateur sur les listes: vrai si la sortie a ØtØ effectuØe avec succ?s, faux sinon. On a donc le droit d Øcrire:

$a = print ("hello ", "word", "\n");

# affichage de "hello word" avec retour à la ligne et $a = 1

On est parfois obligØ de mettre des parenth?ses, en particulier si la premi?re chose afficher commence par une parenth?se ouvrante; exemples:

print (2+3),"coucou";

# faux; n’affiche que 5, ignore "coucou" print ( (2+3), "coucou");     # affichage de 5coucou print 2+3, "coucou";     # idem

• printf

Cet opØrateur prend une liste de param?tres (encadrØs ou non par des parenth?ses). Le premier param?tre est une cha ne de contr le des formats, indiquant comment afficher les param?tres restant. C est comme le printf du C; exemple: printf "%15s %5d %10.2f \n", $s, $n, $r ;


 

2.6. LES EXPRESSIONS REGULIERES

Nous en avons parlØ rapidement au paragraphe 1.4. Nous allons maintenant les Øtudier plus en dØtail.

Une expression rØguli?re est un pattern qui est recherchØ dans une cha ne de caract?res. Le rØsultat de la recherche peut Œtre positif ou nØgatif. Parfois, c est simplement ce rØsultat qui nous intØresse; parfois, on souhaite pouvoir remplacer le pattern par une autre cha ne.

Les expressions rØguli?res sont utilisØes par de nombreux programmes Unix comme grep, sed, awk, ed, vi, emacs et les diffØrents shells. N importe quelle expression rØguli?re qui peut Œtre dØcrite avec l un des outils Unix peut Øgalement Œtre Øcrite en Perl, sans nØcessairement utiliser les mŒmes caract?res.

2.6.1. Utilisations simples des expressions rØguli?res

Si l on dØsire rØcupØrer les lignes du fichier nomfic comportant la cha ne abc, on utilise la commande:

> grep abc nomfic

Ici, abc est l expression rØguli?re utilisØe par grep pour tester toutes les lignes de nomfic. Les lignes matchØes sont envoyØes sur la sortie standard.

En Perl, abc est considØrØe comme une expression rØguli?re si elle est encadrØe par des slashes; le script Perl Øquivalent la commande grep prØcØdente est donc:

while (<>)

{if (/abc/)

   { print; }  }

Le matching est effectuØ sur la variable $_, qui contient la ligne courante du fichier passØ en param?tre au script. La sortie se fait sur la sortie standard.

Si maintenant on veut trouver les lignes de nomfic contenant un a suivi de zØro ou plusieurs b et d un c, on peut utiliser la commande:

> grep "ab*c" nomfic

On est obligØ d utiliser des doubles quotes pour la cha ne contenant l astØrisque, si l on ne veut pas que le shell l interpr?te comme un nom de fichier.

En Perl, cela est rØalisØ de la fa on suivante:

while (<>) {if (/ab*c/)

   { print; }  }

Un autre opØrateur sur les expressions rØguli?res est l opØrateur de substitution s///, qui remplace la partie de la cha ne matchØe par l expression rØguli?re par une autre cha ne. Exemple:

s/ab*c/def/;

La cha ne (ici $_) est parcourue. On y recherche un a suivi de zØro ou plusieurs b et d un c. Si la recherche est fructueuse, la partie de $_ matchØe est remplacØe par la cha ne def. Sinon, il ne se passe rien.

2.6.2. Les patterns

Il y a diffØrentes sortes de patterns:

Les patterns     un seul caract?re

Le plus simple est un unique caract?re qui se matche lui-mŒme. Ainsi, /a/ permet de rechercher la lettre a dans une cha ne.

Le point, ".", permet de matcher n importe quel caract?re sauf newline (\n). Par exemple, /a./ permet de matcher toute sØquence de deux caract?res commen ant par a et n Øtant pas "a\n".

Une classe de caract?res pour le matching est reprØsentØe par deux crochets encadrant une liste de caract?res. Un seul de ces caract?res doit Œtre prØsent dans la ligne parcourue pour que le matching fonctionne. Exemple:

/[abcde]/

matche l un des cinq caract?res, en minuscule.

Si l on veut inclure le crochet fermant dans la liste des caract?res matcher, il doit Œtre prØcØdØ par un antislash ou se trouver en dØbut de liste. On peut figurer un intervalle de valeurs en utilisant le tiret (-). Si celui-ci doit figurer dans la liste de caract?res matcher, il suffit de le faire prØcØder d un antislash.

Exemple:

                   /[a-e]/        # même chose que l’exemple précédent

Il existe un caract?re de nØgation: ^; placØ juste apr?s le crochet ouvrant, il permet de nier une classe de caract?res: tout caract?re ne se trouvant pas dans la liste sera matchØ. Exemple:

/[^0-9]/ # matche tout ce qui n’est pas un chiffre

Si on veut faire figurer ^ dans la liste des caract?res matcher, il suffit de le faire prØcØder d un antislash.

Certaines classes sont prØdØfinies:

Construction

Classe Øquivalente

Construction nØgative

Classe Øquivalente

/d     (digits)

[0-9]

/D     (digits, not!)

[^0-9]

/w    (words)

[a-zA-Z0-9]

/W    (words, not!)

[^a-zA-Z0-9]

/s     (space)

[ \r \n \f \t]

/S      (space, not!)

[^ \r \n \f \t]

Les patterns groupants

1.    Les sØquences

Comme nous l avons vu plus haut, abc matche un a suivi d un b suivi d un c. On appelle cela une sØquence.

2.    Les multiplicateurs

Nous avons dØj vu l astØrisque (*); elle signifie « 0 ou plusieurs » pour le caract?re immØdiatement prØcØdent.

On dispose Øgalement des caract?res + et ?, signifiant respectivement « 1 ou plusieurs » et « 0 ou 1 » pour le caract?re immØdiatement prØcØdent. Exemple:

 /fo+ba?r/

matche un f suivi d un ou plusieurs o, suivi d un b, suivi de zØro ou un a, suivi d un r.

Ces trois patterns groupants sont dits gloutons; en effet, s ils peuvent matcher plusieurs fois le mŒme caract?re, ils en matcheront toujours le maximum. Exemple:

 $_ = "Salut XXXXXXXXXX ! "; s/X*/pascal/;   # on obtient "Salut pascal ! ";

Si on a besoin d Œtre plus prØcis quant au nombre de rØpØtitions du mŒme caract?re matcher, il faut utiliser le multiplicateur gØnØral. Il se prØsente sous la forme de deux accolades renfermant un ou deux nombres sØparØs par une virgule. Exemple:

/X{5,10}/

Comme pour les trois multiplicateurs dØj rencontrØs, le caract?re immØdiatement prØcØdent (ici, "X") doit Œtre trouvØ avec un nombre de rØpØtitions compris entre les deux nombres contenus dans les accolades (ici, entre 5 et 10). On peut aussi avoir les patterns:

 /X{5,}/ # matche au moins 5 répétitions de X

               /X{5}/    # matche exactement 5 répétitions de X

 /X{0,5}/ # matche au plus 5 répétitions de X

 /a.{5}b/ # matche un a suivi de 5 caractères différents de

newline, suivis d’un b

S il y a deux multiplicateurs dans une mŒme expression, c est le plus gauche qui est le plus glouton; Exemple:

          $_ = "a xxx c xxxxxxx c xxx d";

          /a.*c.*d/

Le premier ".*" matche tous les caract?res jusqu au deuxi?me c. Ici, ca ne fait pas grande diffØrence, mais nous verrons tout l heure que a peut en avoir.

3. Les parenth?ses pour la mØmorisation

Un autre pattern groupant est la paire de parenth?ses encadrant un pattern. Elle permet de mØmoriser la cha ne matchØe par le pattern qu elle renferme et de la rØfØrencer par la suite. Donc (a) matche toujours un a, ([a-z]) matche toujours n importe quelle lettre minuscule.

Pour rØfØrencer la partie de la cha ne qui a ØtØ mØmorisØe, on utilise un antislash suivi d un entier qui indique de quelle paire de parenth?ses il s agit (on compte partir de 1). Exemple:

/fred(.)barney\1/;

matche une cha ne comportant les caract?res fred, suivis d un caract?re qui n est pas un newline, suivi de barney, suivi du mŒme caract?re que prØcØdemment. Donc la cha ne fredxbarneyx est matchØe; par contre, la cha ne fredxbarneyy ne l est pas. Autre exemple:

 /a(.)b(.)c\2d\1/;

matche un a, suivi d un caract?re (notØ #1), suivi d un b, suivi d un caract?re (notØ #2), suivi d un c, suivi du caract?re #2, suivi d un d, suivi du caract?re #1. On peut enfermer plus d un caract?re dans les parenth?ses; exemple:

/a(.*)b\1c/;

matche un a, suivi une sØquence de caract?res, suivie d un b, suivi de la mŒme sØquence de caract?res, suivie d un c.

Avec l opØrateur de substitution, la structure avec les \1, \2, etc permet d utiliser les morceaux de cha ne mØmorisØs pour la construction de la cha ne de remplacement; exemple:

 $_ = "a xxx b yyy c zzz d";

               s/b(.*)c/d\1e/;                # $_ = "a xxx d yyy e zzz d"

4. Les alternatives

Une construction alternative, telle que a|b|c, est une autre forme de pattern groupant. Elle signifie qu il faut matcher l une des alternatives qu elle comporte (a ou b ou c). Les alternatives peuvent Œtre constituØes de plusieurs caract?res; exemple:

 /coucou|salut/

Remarquez que /a|b|c/ est Øquivalent /[a-c]/.

Les patterns d ancrage

Il y en a quatre. Ils permettent prØciser quel endroit de la cha ne la recherche du pattern doit commencer.

La premi?re paire d ancres vØrifie qu une certaine partie de la cha ne matchØe se trouve ou non l une des extrØmitØs d un mot. Une extrØmitØ de mot est l endroit entre des caract?res matchØs par \w et \W, ou entre des caract?res matchØs par \w et le dØbut ou la fin de la cha ne. \b exige une extrØmitØ de mot l endroit oø il est placØ pour que le matching s effectue. \B exige le contraire. Exemples:

/fred\b/

# matche fred, Alfred, mais pas frederic

/\bwiz/

# matche wizard mais pas qwiz

/\bfred\b/

# matche uniquement fred

/\b+\b/

# matche x+y, mais pas ++ ou +

/\bfred\B/

# matche frederic, mais pas fred flintstone

La deuxi?me paire d ancres vØrifie qu une certaine partie de la cha ne matchØe est au dØbut ou la fin de la cha ne. ^ exige que le pattern qui le suit soit en dØbut de cha ne. $ exige que le pattern qui le prØc?de soit en fin de cha ne.

Exemples:

/^a/

# matche les chaînes commençant par a

/a^/

# matche les chaînes comportant un a, suivi de ^

/\^/

# matche les chaînes contenant le caractère ^

/c$/

# matche les chaînes dont le dernier caractère est un c

/\$/

# matche les chaînes contenant le caractère $

PrioritØ

Comme pour les opØrateurs, il existe des r?gles de prioritØ pour les patterns groupants et d ancrage. Elles sont explicitØes dans le tableau suivant, de la prioritØ la plus grande la plus petite:

Nom

ReprØsentation

Parenth?ses

( )

Les multiplicateurs

* + ? {m,n}

SØquences et ancrages

abc ^ $ \b \B

Alternatives

|

Par exemple, /a|b*/ matche les cha nes contenant un a ou plusieurs b. Par contre /(a|b)*/ matche les cha nes contenant plusieurs a ou plusieurs b.

Quand on utilise les parenth?ses pour la prioritØ, elles dØclenchent Øgalement la mØmorisation. Attention donc lors de l utilisation des \1, \2, etc.

2.6.3. ComplØments sur l opØrateur de matching

Nous avons dØj vu l utilisation la plus simple de cet opØrateur: une expression rØguli?re entre deux slashes. Nous allons prØsent faire la connaissance des autres possibilitØs qu offre cet opØrateur.

Les opØrateurs =~ et !~

Ces opØrateurs sont utilisØs pour effectuer la recherche d un pattern dans une autre cha ne que celle contenue dans $_. Exemple:

$a = "bonjour tout le monde! ";

                   $a =~ /^bon/;            # $a contient vrai

$chaine !~ /pattern/;

# équivaut à !($chaine=~/pattern/);

La cible des opØrateurs =~ et !~ peut Œtre n importe quelle expression dont la valeur est une cha ne. On peut donc les utiliser avec <STDIN>; exemple:

print "Bonjour, professeur Falken! Vous voulez bien jouer avec moi? " if (<STDIN> =~ /^[oO]/)

{ print "Je vous propose une guerre thermonucléaire globale." }

•  L option i

Cette option permet d ignorer la diffØrence entre minuscules et majuscules. On la place apr?s le deuxi?me slash. Les lettres du pattern matchent alors les lettres de la cha ne, qu elles soient minuscules ou majuscules. L exemple prØcØdent devient:

print "Bonjour, professeur Falken! Vous voulez bien jouer avec moi? " if ( <STDIN> =~ /^o/i )

{ print "Je vous propose une guerre thermonucléaire globale." }

•  Utilisation d un autre dØlimiteur

Lorsqu on doit inclure un slash dans le pattern, celui-ci doit Œtre prØcØdØ par un antislash. Exemple:

$path =~ /^\/usr\/etc/;

Ce n est donc pas marrant s il y a plusieurs slashes dans le pattern. Perl permet donc, ici encore, de se simplifier la vie en autorisant tout autre caract?re non alphanumØrique servir de dØlimiteur, condition qu il soit prØcØdØ d un m (matching!). Exemple:

$path =~ m#^/usr/etc#; # # est utilisé comme délimiteur $path =~ m@^/usr/etc@;     # @ est utilisé comme délimiteur

$path =~ m/^\/usr\/etc/;

# / est utilisé comme délimiteur; le m est alors optionnel

•  L interpolation de variable

L interpolation        de        variable           est       effectuØe        avant   l Øvaluation     de        l expression       rØguli?re. Exemple:

$assertion = "Un chasseur sachant chasser";

$mot = "chasseur"; if ($assertion =~ /$mot/ )

 { print "L’assertion contient le mot $mot. "; }

•  Des variables spØciales

Apr?s une reconnaissance de pattern rØussie, les variables $1, $2, etc prennent les mŒmes valeurs que \1, \2, etc. Exemple:

$_ = "ceci est un test";

                   /(\w+)\W+(\w+)/;    # matche les deux premiers mots de $_

# $1 = "ceci", $2 = "est"

On peut aussi rØcupØrer ces valeurs en effectuant le matching dans un contexte de tableau. L exemple prØcØdent peut s Øcrire:

$_ = "ceci est un test";

($premier, $deuxième) = /(\w+)\W+(\w+)/; # $premier = "ceci", $deuxième = "est"

$1 et $2 demeurent inchangØes: $1 = "ceci" et $2 = "est".

Il existe trois autres variables, accessibles en lecture uniquement, comme $1, $2, etc:

1.    $& contient le bout de cha ne matchØ

2.    $· contient le bout de cha ne situØ apr?s la partie matchØe3. $‘ contient le bout de cha ne situØ avant la partie matchØe Exemple:

$_ = "ceci est un test simple";

                   /te.*t/;       # matche test

#$& = "test", $´ = "simple", $` = "ceci est un"

2.6.4. Les substitutions

Nous avons dØj           vu la plus simple utilisation de cet opØrateur; complØtons maintenant nos connaissances.

Si l on souhaite que la substitution soit effectuØe chaque occurrence du pattern, il suffit d ajouter un g apr?s le dernier slash; exemple:

$_ = "coucou! ca va? "; s/ou/ri/g;     # $_ = "cricri! ca va? "

L interpolation de variable a lieu dans la cha ne de remplacement; exemple:

$_ = "bonjour, pascal! "; $autre = "seb";

s/pascal/$autre/;# $_ = "bonjour, seb! "

Les caract?res de la cha ne de remplacement ne sont donc pas forcØment fixØs l avance et peuvent mŒme Œtre extraits des caract?res matchØs; exemple:

$_ = "ceci est un test";

             s/(\w+)/<$1>/;        $_ = "<ceci> <est> <un> <test>"

Si on ajoute un i apr?s le dernier slash, les majuscules ou les minuscules sont ignorØes dans l expression rØguli?re (mŒme chose qu avec le matching).

On peut Øgalement utiliser des dØlimiteurs diffØrents du slash; exemple:

s#fred#barney#;

# il suffit d’utiliser trois fois le même caractère

L opØrateur =~ permet d effectuer la substitution sur une autre cha ne que celle contenue par $_. Exemple:

$lequel = "ceci est un test";

$lequel =~ s/test/quizz/; # $lequel = "ceci est un quizz"

2.6.5. Les opØrateurs split() et join()

L opØrateur split()

 Cet opØrateur prend comme param?tres une expression rØguli?re et une cha ne, et cherche toutes les occurrences de l expression rØguli?re dans la cha ne. Les parties de la cha ne qui n ont pas ØtØ matchØes sont retournØes sous forme d une liste. Exemple:

 $ligne = "merlyn::118:10:Randal:/home/merlyn:/usr/bin/perl";

 @champs = split(/:/, $ligne);

 # décompose $ligne en prenant : comme délimiteur

 # @champs = ("merlyn","","118","10","Randal","/home/merlyn",

  "/usr/bin/perl")

     La cha ne par dØfaut pour cet opØrateur est la variable $_; le pattern par dØfaut est /\s+/. Exemple:

              @mots = split;      # équivalent à @mots = split(/\s+/, $_)

L opØrateur join()

Cet opØrateur prend une liste de valeurs et les recolle en pla ant zØro, un ou plusieurs caract?res collants entre chaque ØlØment de la liste; exemple:

$grosse_chaine = join($colle, @liste);

# $colle contient les caractères collants

Pour recoller la ligne de /etc/passwd dØcoupØe prØcØdemment, on peut utiliser l instruction:

$resultat = join(":", @champs);

2.7. LES FONCTIONS

L utilisateur peut dØfinir ses propres fonctions en Perl. On parle alors plut t de subroutine ou sub.

2.7.1. DØfinition d une subroutine

Une subroutine dans un programme Perl est dØfinie comme suit:

sub nom_subroutine { instruction_1;    instruction_2;

    instruction_n;

}

Un nom de subroutine suit les mŒmes r?gles que les noms de variables, de tableaux et de tableaux associatifs. Le bloc d instructions suivant le nom de la subroutine devient sa dØfinition. Lorsqu’on fait appel la subroutine, c est le bloc d instructions qui est exØcutØ et tout rØsultat est renvoyØ l utilisateur.

Les subroutines peuvent Œtre dØfinies n importe oø dans le programme. Les dØfinitions des subroutines sont globales.

A l intØrieur d une subroutine, on peut manipuler des variables partagØes avec le reste du programme (globales donc!).

2.7.2. L appel       une subroutine

Pour faire appel une subroutine, n importe oø dans le programme, on fait prØcØder son nom par le symbole &; exemple:

for ( $i=&val-init; $i<&val_test; $i+=&val_increment)

{ }

Une subroutine peut faire appel        d autres subroutines faisant elles-mŒmes appel      d autres subroutines

2.7.3. RØsultats d une fonction

Le rØsultat d une subroutine est la valeur de la derni?re expression ØvaluØe dans le corps de la subroutine, chaque appel. Une subroutine peut Øgalement retourner une liste, dans un contexte de tableau. Exemples:

sub somme_a+b { $a + $b; }

$a = 3; $b = 5;

             $c = &somme_a+b;      # $c = 8

sub choix_a_ou_b

{ if ($a > 0)

   {  print "je choisis a ($a) \n";

       $a; }    else

   { print "je choisis b ($b) \n";

       $b; }

}

Dans ce deuxi?me exemple, la derni?re expression ØvaluØe est soit $a soit $b. Si on avait inversØ les lignes avec $a et le print, on aurait 1 comme valeur de retour (print a marchØ) plut t que $a.

2.7.4. Les param?tres

Si l appel une subroutine est suivi d une liste parenthØsØe, la liste est automatiquement rangØe dans le tableau @_ pendant la durØe d utilisation de la subroutine. Celle-ci peut accØder ce tableau pour savoir combien il y a d arguments et quelle est leur valeur. Exemple:

sub bonjour_ a_qui

{ print "bonjour, $_[0] ! \n"; }

$_[0] est le premier ØlØment de la liste d arguments. Ne pas le confondre avec la variable $_!

Un appel possible de cette subroutine:

&bonjour_a_qui ("cricri");

# affichage de "bonjour, cricri !"

Un exemple de subroutine utilisant plus d un param?tre:

sub parler

{ print "$_[0], $_[1] ! \n"; }

&parler ("bonjour", "cricri");

# affichage de "bonjour, cricri !"

Les param?tres en trop sont ignorØs. Les param?tres manquant se voient attribuer la valeur undef.

@_ est local la subroutine. S il existait une valeur globale pour @_, elle est sauvegardØe avant l appel la subroutine et restaurØe lorsque l exØcution de la subroutine est achevØe. Une subroutine peut donc passer des arguments une autre subroutine sans pour autant perdre sa propre liste d arguments.

Reprenons l exemple de somme_a+b en le modifiant de fa on pouvoir effectuer la somme de deux nombres, quels qu ils soient:

sub somme2

{ $_[0] + $_[1] ; }

             $c = &somme2( 3, 5);        # $c = 8

Si maintenant on veut faire la somme de plusieurs nombres:

sub somme

             { $somme = 0 ;              # initialisation

   foreach ( @_ )

               { $somme += $_ ; }       # somme de chaque élément

   $somme ;

   # dernière expression évaluée: le résultat

}

             $c = &somme ( 3, 4, 6, 7);       # $c = 20

2.7.5. Les variables locales

L opØrateur local() permet de crØer des variables locales une subroutine. Il re oit une liste de noms de variables et en crØe des instanciations. Si ces variables existaient dØj en tant que variables globales ou locales d autres fonctions, elles sont sauvegardØes avant l exØcution de la subroutine qui les utilise et restaurØes lorsque cette exØcution est terminØe. Reprenons l exemple ci-dessus:

sub somme

             { local ($somme) ;          # fait de $somme une variable locale

                $somme = 0 ;             # initialisation

   foreach ( @_ )

               { $somme += $_ ; }       # somme de chaque élément

   $somme ;

  # dernière expression évaluée: le résultat }

Le rØsultat de local() est une liste de variables pouvant Œtre affectØes. On peut donner des valeurs initiales toutes ces nouvelles variables; sinon, elles sont initialisØes avec undef. On peut donc modifier l exemple prØcØdent en rempla ant les deux premi?res lignes par:

local ($somme) = 0 ;

2.8. DIVERSES STRUCTURES DE CONTROLE

2.8.1. L opØrateur last

Cet opØrateur permet de sortir plus t t d une boucle (c est l Øquivalent du break en C). L exØcution se poursuit avec l instruction situØe immØdiatement apr?s la boucle. Exemple:

while (expression_1) { instruction_11;    instruction_12;

   if (expression_2)    { instruction_21;       instruction_22;       last; # permet de sortir du while

    } instruction_1n;

}

# on reprend ici avec last

last n a cet effet qu avec les blocs de boucle for, foreach, while et les blocs indØpendants (ne se rapportant pas un if ou une subroutine ou un bloc plus important).

2.8.2. L opØrateur next

Comme last, next modifie l ordre sØquentiel d exØcution. Cet opØrateur permet de sauter l exØcution d un corps de boucle, sans terminer le bloc. Il est utilisØ comme suit:

while (expression_1) { instruction_11;    instruction_12;

   if (expression_2)    { instruction_21;       instruction_22;       next;

    } instruction_1n;

   # on reprend ici avec next

}

2.8.3. L opØrateur redo

Cet opØrateur permet de revenir au dØbut du bloc d itØrations et donc de l exØcuter de nouveau, sans rØØvaluation de l expression de contr le; exemple:

while (expression_1) { # on revient ici avec redo    instruction_11; instruction_12;

   if (expression_2)    { instruction_21;       instruction_22;       redo;     } instruction_1n;

}

2.8.4. Les blocs ØtiquetØs

Pour sortir de plusieurs blocs la fois, il suffit d utiliser les opØrateurs next, redo et last et d Øtiqueter les blocs.

Une Øtiquette est un nom suivant les mŒmes r?gles que les noms de variables scalaires, de tableaux ou de subroutines. Cependant ce nom n est prØcØdØ par aucun symbole spØcial; donc une Øtiquette telle que print est interdite, car elle serait confondue avec l opØrateur print. C est pourquoi il est conseillØ que le nom d une Øtiquette soit composØ uniquement de lettres majuscules et de chiffres.

L Øtiquette est placØe en tŒte du bloc Øtiqueter; passØe en param?tre next, last ou redo, elle indique le bloc concernØ par ces opØrateurs.

Exemple:

EXTERIEUR:

for ( $i = 1; $i <= 10; $i++)

{ INTERIEUR:    for ( $j = 1; $j <= 10; $j++)

   {  if ( $i * $j == 63 )

       { print "$i fois $j égal 63 !\n";            last EXTERIEUR;

        }

        if ( $j >= $i )

        { next EXTERIEUR; }

    }

}

Cet exemple teste des valeurs successives de $i et $j jusqu      ce que leur produit soit Øgal

63. Lorsque la paire est trouvØe, on s arrŒte. On vØrifie toujours que $i est plus grand que $j, sinon on passe la valeur suivante de $i; on testera donc uniquement les paires (1, 1), (2, 1), (2, 2), (3, 1),

Si on avait utilisØ last et next sans Øtiquette et mŒme si on n avait pas ØtiquetØ le bloc le plus interne (INTERIEUR), ces opØrateurs se seraient pourtant rapportØs ce bloc.

On ne peut pas utiliser les Øtiquettes pour entrer dans un bloc, mais seulement pour en sortir; les opØrateurs next, last et redo doivent Œtre dans ce bloc.

2.8.5. Les modificateurs d expression

Une autre fa on de dire: « Si ceci, alors cela », est: « cela si ceci ». Perl permet ce genre de raccourci, comme ceci:

une_expression if expression_de_contrôle;

L expression de contr le est ØvaluØe en premier; si elle est vraie, alors une_expression est exØcutØe. Cela revient :

if (expression_de_contrôle) { une_expression ; }

mais il y a moins de chose taper. Cependant une_expression doit Œtre une unique expression (et non un bloc d instructions).

Un exemple d utilisation: sortir d une boucle quand une certaine condition est vØrifiØe:

LIGNE:

while (<STDIN>)

{last LIGNE if  /^Date/ ;}

De la mŒme fa on, il existe:

exp2 while exp1; # équivaut à while (exp1) { exp2;} exp2 unless exp1;# équivaut à unless (exp1) { exp2;} exp2 until exp1; # équivaut à until (exp1) { exp2;}

2.8.6. &&, || et ?: comme structures de contr le

Une autre fa on d Øcrire: « si ceci, alors cela », est d utiliser le et-logique:

ceci && cela ;

Comment   a peut marcher? Et bien:

•  si ceci est vraie, alors l expression ci-dessus n est pas encore totalement ØvaluØe puisqu elle dØpend de cela. Donc cela doit Œtre ØvaluØe.

•  si ceci est fausse, alors l expression ci-dessus est fausse aussi; pas besoin d Øvaluer cela.

Donc cela est ØvaluØe uniquement si ceci est vraie; c est bien Øquivalent aux deux constructions que nous avons vues prØcØdemment.

De la mŒme fa on, le ou-logique peut remplacer la structure unless; exemple:

ceci || cela;

Si ceci est vraie, alors inutile d Øvaluer cela; sinon, cela est ØvaluØe.

Enfin, il existe l opØrateur ternaire:

exp1 ? exp2 : exp3 ; qui Øvalue exp2 si exp1 est vraie, et exp3 sinon. Cela revient :

if (exp1) { exp2 ; } else { exp3 ; } mais il n y a pas toute cette ponctuation!

2.9. LES MANIPULATEURS DE FICHIERS ET LES TESTS SUR LES FICHIERS

2.9.1. Les manipulateurs de fichiers ou filehandles

Ils ont ØtØ prØsentØs au paragraphe 1.1.1., mais a ne fait jamais de mal de rØpØter un peu!

Un manipulateur de fichier est le nom, dans un programme Perl, d une connexion entrØe/sortie entre le processus Perl et le monde extØrieur.

Nous en avons dØj utilisØ; par exemple STDIN est le filehandle dØsignant la connexion entre le processus Perl et l entrØe standard d Unix. Perl dispose aussi de STDOUT et STDERR.

Un nom de filehandle suit les mŒmes r?gles que les noms d Øtiquettes, de tableaux, de subroutines Cependant, comme les Øtiquettes, il n est prØcØdØ par aucun symbole particulier. Il est donc conseillØ d utiliser des majuscules et de ne pas interfØrer avec les mots rØservØs.

2.9.2. Ouverture et fermeture de filehandle

STDIN, STDOUT et STDERR sont ouverts automatiquement par le p?re du processus Perl. Pour ouvrir d autres filehandles, on utilise la fonction open(); exemple:

             open ( MANIP, "nomfic");         # ouverture en lecture

MANIP est le nouveau manipulateur de fichier et nomfic est le nom du fichier Unix associØ ce nouveau filehandle. Cette instruction ouvre le filehandle en lecture; pour l ouvrir en Øcriture, on utilise encore open mais on fait prØcØder le nom du fichier par le signe supØrieur:

             open ( MANIP, "> nomfic");       # ouverture en écriture

Pour ouvrir un fichier et Øcrire   la suite de ce qu il contient dØj , il suffit d Øcrire:

open ( MANIP, ">> nomfic");

Ces trois formes de open retournent vrai si l ouverture s est dØroulØe avec succ?s, faux sinon.

Pour fermer un filehandle, on utilise l opØrateur close() comme suit:

close ( MANIP);

Rouvrir un filehandle a pour effet de refermer automatiquement le fichier associØ par le prØcØdent open.

La fin d exØcution du programme Perl a pour effet de refermer automatiquement tous les fichiers. close() n est donc pas forcØment nØcessaire.

2.9.3. L opØrateur die()

Un filehandle qui n a pas ØtØ ouvert avec succ?s peut continuer d Œtre utilisØ sans qu il y ait aucune indication de la part du programme. Si une lecture y est effectuØe, le caract?re de fin de fichier est retournØ; toute donnØe qu on essaiera d y Øcrire sera perdue.

Bien sßr, on peut utiliser une structure de contr le avec un message d erreur s affichant si l ouverture n a pas marchØ.

Mais Perl permet, ici encore, de se simplifier la vie: l opØrateur die() prend comme argument une cha ne de caract?res qu il va Øcrire sur l erreur standard, et tue le processus Perl (celui du programme) avec un exit Unix de statu non nul. CombinØ avec le ou-logique, notre test est maintenant tr?s simple:

open(MANIP, "> nomfic") || die ("Impossible d’ouvrir nomfic!");

Cela se lit: « Ouvre ce fichier ou meurt! ». die() n est exØcutØ que si open retourne faux. Le message renvoyØ la mort du processus comporte le nom du programme Perl et le numØro de ligne oø a n a pas marchØ. Si on ne dØsire pas avoir ces informations, il suffit de terminer la cha ne de caract?res de die() par le caract?re "\n".

2.9.4. Utilisation des filehandles

Un filehandle ouvert en lecture peut Œtre lu tout comme STDIN; exemple:

open(EP, "/etc/passwd"); while (<EP>) { chop;    print "j’ai vu $_ dans le fichier des mots de passe! "; }

Un filehandle ouvert en Øcriture doit Œtre passØ en argument print comme suit:

print MANIP "fini de rigoler!";

Par ailleurs, nous avons vu que, par dØfaut, la sortie se fait sur STDOUT:

             print STDOUT "coucou!";           # équivaut à print "coucou! ";

2.9.5. Les tests sur les fichiers

Ils sont regroupØs dans le tableau suivant:

-r                         fichier ou rØpertoire accessible en lecture

-w             fichier ou rØpertoire accessible en Øcriture

-x               fichier ou rØpertoire exØcutable

-o                        fichier ou rØpertoire propriØtØ de l utilisateur

-R fichier ou rØpertoire pouvant Œtre lu par l utilisateur rØel, et non par l utilisateur effectif (diff?re de -r pour les programmes setuid)

-W              fichier ou rØpertoire pouvant Œtre Øcrit par l utilisateur rØel, et non par l utilisateur effectif (diff?re de -w pour les programmes setuid)

-X              fichier ou rØpertoire exØcutable par l utilisateur rØel, et non par l utilisateur effectif (diff?re de -x pour les programmes setuid)

-O fichier ou rØpertoire propriØtØ du l utilisateur rØel, et non de l utilisateur effectif (diff?re de -o pour les programmes setuid)

-e                         fichier ou rØpertoire existant

-z                          fichier existant, de taille nulle

-s                        fichier ou rØpertoire existant et comptant un nombre non nul de caract?res

-f                         l entrØe est un fichier

-d                        l entrØe est un rØpertoire

-l                          l entrØe est un lien symbolique

-S                         l entrØe est une socket

-p                        l entrØe est un pipe portant un nom (fifo)

-b              l entrØe est un fichier avec bloc spØcial

-c               l entrØe est un fichier de caract?res spØciaux

-u                        fichier ou rØpertoire ayant le bit 11 (setuid) positionnØ  1

-g                         fichier ou rØpertoire ayant le bit 10 (setgid) positionnØ   1

-k                        fichier ou rØpertoire ayant le bit s positionnØ

-t                          isatty() sur le filehandle retourne vrai

-T                         fichier texte

-B                         fichier binaire

-M                        age de la derni?re modification du fichier en jours

-A                         age du dernier acc?s au fichier en jours

-C                         age de la derni?re modification d inode du fichier en jours

La plupart de ces tests retournent vrai ou faux.

Cependant, l opØrateur -s retourne vrai si le fichier est non vide, mais c est un vrai particulier: c est le nombre d octets du fichier, qui est ØvaluØ vrai si ce n est pas 0.

Les opØrateurs d age -M, -A, -C retournent le nombre de jours qui se sont ØcoulØs depuis la derni?re modification, le dernier acc?s au fichier et la derni?re modification d inode de ce fichier. Cet age a une rØsolution de 1 seconde et peut avoir une valeur dØcimale: 36 heures sont notØes 1,5 jours.

Tous ces opØrateurs peuvent prendre comme param?tre aussi bien un filehandle qu un nom de fichier. Si on ne leur passe pas de param?tre, ils prennent comme opØrande par dØfaut le fichier dont le nom est contenu dans la variable $_; par exemple, pour tester en lecture une liste de nom de fichiers il suffit d Øcrire:

foreach ( @liste_nom_fichiers )

{ print "$_ est accessible en lecture \n" if -r ; }

2.9.6. Les opØrateurs stat() et lstat()

Pour obtenir toute autre information sur un fichier, on utilise l opØrateur stat() qui retourne pratiquement tout ce que l’appel syst?me stat() retourne. Cet opØrateur prend un filehandle ou une expression s Øvaluant un nom de fichier comme param?tre. Il retourne soit la valeur undef si l instruction a ØchouØ, soit un tableau de 13 ØlØments, dØcrit en dØtail dans la page man de stat(2).

L appel stat() avec un nom de lien symbolique renvoie ce sur quoi ce lien pointe, mais pas d information sur le lien lui-mŒme. Pour obtenir ces informations, on dispose de l opØrateur lstat().

Comme pour les tests sur les fichiers, stat() et lstat() prennent $_ comme param?tre par dØfaut.

2.9.7. Le filehandle _

A chaque utilisation de -r, -w, stat() etc, Perl doit demander au syst?me un buffer stat au sujet du fichier (le buffer rØsultat de l’appel syst?me stat). Cela signifie que si l on demande si un fichier est accessible en Øcriture et en lecture, Perl ira chercher deux fois la mŒme information.

Pour Øviter a, on dispose du filehandle _. PassØ comme param?tre un test de fichier, stat() ou lstat(), il indique Perl de rØutiliser le buffer stat obtenu lors du dernier test de fichier ou du dernier appel stat() ou lstat(). Exemple:

if ( -r $nomfic && -w _ )

{ print "$nomfic est accessible en écriture et en lecture \n"; }

Pour le premier test, on utilise $nomfic pour obtenir du syst?me d exploitation les donnØes concernant ce fichier; pour le deuxi?me test, par contre, on utilise _: les donnØes obtenues par le premier test sont rØutilisØes.


 

2.10. LES FORMATS

2.10.1. Qu est-ce qu un format?

Perl dispose d un outil de mise en page, appelØ format. Un format dØfinit une partie constante (entŒte, labels, texte fixe, etc.) et une partie variable (les donnØes auxquelles va s appliquer le format). L utilisation d un format consiste en trois points:

1.    dØfinir le format

2.    charger les donnØes          afficher dans les parties variables du format

3.    faire appel au format

Le premier point est effectuØ une fois, n importe oø dans le texte du programme, les deux autres sont effectuØs de fa on rØpØtitives.

2.10.2. DØfinition d un format

Un format est dØfini par une dØfinition de format. Celle-ci peut figurer n importe oø dans le texte du programme, comme les subroutines. Elle est de la forme:

format nomdeformat = ligne de champ valeur_1, valeur_2, valeur_3 ligne de champ valeur_1, valeur_2, valeur_3 ligne de champ valeur_1, valeur_2, valeur_3 .

La premi?re ligne contient le mot rØservØ format, suivi du nom du format et du signe =. Le nom du format doit vØrifier les mŒmes r?gles que les autres noms de variables. Il peut cependant Œtre un mot rØservØ, puisqu il n est pas utilisØ dans le corps du programme (si ce n est en tant que cha ne). Vient ensuite le gabarit, dont la fin est indiquØe par une ligne contenant un seul et unique point. Attention, les gabarits sont sensibles aux espaces.

La dØfinition du gabarit contient un certain nombre de lignes de champ. Chacune d elles peut contenir du texte fixe, texte qui sera affichØ tel quel chaque appel du format. Les lignes de champ peuvent comporter des fieldholders pour le texte variable; exemple:

Bonjour! Mon nom est @<<<<<<<<<<

$nom

Le fieldholder est @<<<<<<<<<<; il spØcifie un champ de 11 caract?res avec alignement gauche.

Si une ligne comporte plusieurs fieldholders, on doit spØcifier autant de valeurs; celles-ci sont alors sØparØes par une virgule; exemple:

Bonjour! Mon nom est @<<<<<<<<<<; j’ai @<< ans

$nom, $age

Une ligne de champ ne comportant pas de fieldholders n est donc pas suivie par une ligne de valeurs.

Les espaces sont ignorØs dans la ligne de valeurs. Les valeurs sont prises en compte en tant que scalaires; donc toute expression est ØvaluØe dans un contexte scalaire.

2.10.3. L appel       un format

On fait appel un format avec l opØrateur write. Celui-ci prend le nom d un filehandle comme param?tre et gØn?re du texte pour ce filehandle, avec le format courant de ce filehandle. Le format par dØfaut est le format du mŒme nom (pour STDOUT, le format STDOUT est utilisØ par dØfaut). Voyons un exemple concret:

format ETIQUETTEADRESSE= =================================

| @<<<<<<<<<<<<<<< @<<<<<<<<<<<<<|

             $nom,                 $prenom

| @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<| $adresse

| @<<<< @<<<<<<<<<<<<<<<<<<<<<<<<|

$code_postal, $ville

================================= .

open(ETIQUETTEADRESSE, ">etiquette-a-imprimer") ||     die ("Création impossible! ");

open (ADRESSES, "adresses") || die ("Impossible d’ouvrir adresses! ");

while (<ADRESSES>)

{ chop;

   ($nom, $prénom, $adresse, $code_postal, $ville) = split (/:/);

   write ETIQUETTEADRESSE;

}

On commence par dØfinir un format pour les Øtiquettes. Notez qu on lui donne le mŒme nom qu au filehandle utilisØ pour la sortie. On ouvre celui-ci et le filehandle contenant les adresses, qui sont censØes avoir le format suivant:

Poiraud:Cecile:19 avenue du docteur Donat:06800:Cagnes-sur-Mer

Chaque ligne de ce filehandle est lue, dØcoupØe, et les 5 morceaux sont affectØs aux 5 champs de l Øtiquette. Notez que les noms des variables recueillant les morceaux sont les mŒmes que ceux utilisØs dans la dØfinition du format; a aussi, c est important.

Enfin, l opØrateur write fait appel au format. Notez cependant que le param?tre de write est le filehandle sur lequel est effectuØe la sortie et que le format du mŒme nom est utilisØ par dØfaut.

Chaque champ du format est alors remplacØ par la valeur correspondante; exemple:

=================================

            | Poiraud         Cecile         |

| 19 avenue du docteur Donat | | 06800 Cagnes-sur-Mer     |

=================================

2.10.4. ComplØments sur les fieldholders

•  Les champs de texte

La plupart des fieldholders commencent par @. Les caract?res suivant @ indiquent le type du champ; le nombre de caract?res (en incluant @) dØfinit la taille du champ.

Si @ est suivi de signes infØrieur (<), alors le champ est alignement gauche. Si la valeur ne remplit pas totalement le champ, celui-ci est complØtØ droite avec des espaces. Si la valeur est trop longue, elle est automatiquement tronquØe.

Si @ est suivi de signes supØrieur (>), alors le champ est alignement droit (si la valeur est trop courte, le champ est complØtØ         gauche par des espaces).

Si @ est suivi de barres verticales (|), alors le champ est centrØ (si la valeur est trop courte, des espaces sont rajoutØs de part et d autre pour qu elle soit peu pr?s centrØe).

•  Les champs numØriques

Il existe Øgalement des champs numØriques de prØcision fixe. Ces champs commencent aussi par @, et sont suivis d un ou plusieurs # avec, en option, un point (la virgule dØcimale). Ici encore, @ compte comme un caract?re du champ; exemple:

format COMPTE_CL =

Credit: @#####.## Debit: @#####.## Total: @#####.## $credit, $debit, $credit-$debit .

Notez l utilisation d une expression dans le format.

•  Les champs multilignes

Perl s arrŒte normalement au premier newline rencontrØ lorsqu il charge les donnØes dans le format. Cependant, il existe un fieldholder permettant d inclure autant de lignes d informations que l on veut; on le note @*, seul sur une ligne. La ligne suivante dØfinit la valeur qui remplira le champ. Exemple:

format STDOUT =

++++++++++++++

@*

$chaine_des_noms ++++++++++++++ .

$chaine_des_noms =

 "cricri\nseb\ngilles\nxav\npascal\nhugo\nsissou\n"; write;

a pour rØsultat:

++++++++++++++ cricri seb gilles xav pascal hugo sissou +++++++++++++++

Les champs paragraphes

Ils permettent de crØer des paragraphes, les lignes Øtant coupØes la fin d un mot. Le fieldholder est le mŒme que pour les champs de texte, si ce n est qu il commence par ^

(par exemple, ^<<<<<).

La valeur correspondante doit Œtre une variable scalaire contenant du texte.

Lorsque Perl remplit le champ paragraphe, il prend autant de mots dans la variable qu il est possible d en mettre dans le champ. Ces mots sont ØliminØs de la variable. Exemple:

format LES_GENS =

Nom: @<<<<<<<<< Commentaires: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

                               $nom,                                    $commentaire

^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$commentaire

^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$commentaire

^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$commentaire .

La mŒme variable, $commentaire, appara t 4 fois. La premi?re ligne affiche le nom de la personne et les premiers mots de $commentaire. Ces mots sont ØliminØs de la variable et, avec la deuxi?me ligne, l affichage des commentaires se poursuit, de mŒme qu aux lignes 3 et 4.

Si $commentaire ne contient pas assez de mots pour remplir les 4 lignes, elles sont complØtØes par des espaces. Pour Øviter l impression de lignes blanches, il suffit d utiliser l indicateur de suppression tilde (~), qui est transparent l impression et peut figurer n importe oø dans la ligne sur laquelle il porte; exemple:

format LES_GENS =

Nom: @<<<<<<<<< Commentaires: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$nom,

$commentaire

~

^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$commentaire

~

 ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$commentaire

~

 ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$commentaire

.

Si $commentaire est trop longue, inutile de copier 20 fois les deux derni?res lignes en espØrant que a suffira. Perl permet de faire a tranquillement. Toute ligne contenant deux tildes successifs (~~) sera rØpØtØe automatiquement jusqu ce qu elle affiche une ligne enti?rement vide. Notre exemple devient alors:

format LES_GENS =

Nom: @<<<<<<<<< Commentaires: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

                               $nom,                $commentaire

                   ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$commentaire .

2.10.5. Le format haut-de-page

Perl permet de dØfinir un format haut-de-page, qui enclenche un mode de pagination. Perl compte le nombre de lignes gØnØrØes par n importe quel appel un format pour un mŒme filehandle. Lorsque le format courant ne loge pas sur ce qu il reste de la page, Perl place un formfeed , effectue un appel automatique au format haut-de-page et continue l affichage sur la page suivante.

Le format haut-de-page est dØfini comme n importe quel format. Son nom par dØfaut est le nom du filehandle suivi de _TOP.

La variable $% contient le nombre d appels au format haut-de-page pour un mŒme filehandle; elle peut donc Œtre utilisØe pour numØroter les pages. L exemple suivant de format haut-depage permet d Øviter que les Øtiquettes de l exemple prØcØdent soient coupØes au changement de page et de numØroter les pages d Øtiquettes:

format ETIQUETTEADRESSE_TOP =

Mes Adresses -- Page @<     $% .

La longueur par dØfaut d une page est de 60 lignes.

2.10.6. Remplacer les valeurs par dØfaut par des formats

L opØrateur select()

     Nous avons vu que le filehandle par dØfaut de print est STDOUT. En fait, pas vraiment. Le vØritable filehandle par dØfaut de print, de write, est le filehandle courant.

 STDOUT est le premier filehandle courant; cependant, on peut modifier ce filehandle avec l opØrateur select(), qui prend comme unique param?tre un nom de filehandle. Une fois que le filehandle courant est modifiØ, cela affecte toutes les opØrations venir faisant appel lui. Exemple:

 print "Bonjour tout le monde! "; # affichage sur STDOUT  select (LOGFILE);

 # le filehandle courant est maintenant LOGFILE

 print "Coucou! "; # affichage dans LOGFILE  select (STDOUT);

 # STDOUT est de nouveau le filehandle courant

                print "Ca va? ";               # affichage sur STDOUT

 Il faut Œtre prudent! Des subroutines peuvent modifier le filehandle courant; on peut alors avoir des surprises. Heureusement, select() retourne le nom de l ancien filehandle courant, ce qui permet de le rØtablir en fin d exØcution de la subroutine. Exemple:

 $vieux_nom = select(LOGFILE);

 # sauvegarde du nom de l’ancien filehandle courant  print "Coucou! ";  select($vieux_nom);    # restaure le filehandle précédent

Pour changer le nom d un format

 Le format par dØfaut pour un certain filehandle est le format du mŒme nom. Cependant, on peut associer au filehandle courant le format dont le nom figure dans la variable $~. Cette variable contient le format courant du filehandle courant.  Si l on veut utiliser le format ETIQUETTEADRESSE pour STDOUT, il suffit d Øcrire:

 $~ = ETIQUETTEADRESSE;

     Si l on veut associer le format RESUME au filehandle RAPPORT:

 $vieux_nom = select(RAPPORT);

 # changement de filehandle courant

 $~ = "RESUME";

 # format pour le filehandle courant

                                                  # code

 write RAPPORT;

 # impression dans RAPPORT avec le format RESUME  select($vieux_nom);

 # retour à l’ancien filehandle courant

•  Pour changer le nom du format haut-de-page

 Il suffit de donner la variable $^ le nom du format haut-de-page appliquer au filehandle courant. On peut consulter cette variable pour conna tre le format haut-de-page du filehandle courant.

•  Pour changer la longueur d une page

 Nous avons vu que, par dØfaut, une page contient 60 lignes. Cependant, on dispose de la variable $=; elle contient le nombre courant de lignes par page pour le filehandle courant et peut Œtre modifiØe.

•  Pour changer de position dans la page

Si on print du texte dans un filehandle, le compteur de lignes du filehandle devient faux puisque Perl ne compte que les lignes issues d un write. Si l on veut que le compteur de Perl reste jour, il suffit de modifier la variable $-. Cette variable contient le nombre de lignes restant dans la page courante du filehandle courant. Chaque write dØcrØmente cette variable du nombre de lignes effectivement imprimØes; lorsque $- = 0, un appel au format haut-de-page est effectuØ et $- prend pour valeur $=.

En dØbut de programme, $- vaut zØro pour tous les filehandles.

2.11. LES REPERTOIRES

2.11.1. Se dØplacer dans l arborescence

L opØrateur Perl chdir() permet de modifier le rØpertoire courant d un processus. Il prend comme param?tre une expression s Øvaluant un nom de rØpertoire et attribue cette valeur au rØpertoire courant. Il retourne vrai si cette modification a bien pu Œtre effectuØe, faux sinon. Exemple:

chdir ( "/etc" ) || die ( "cd /etc impossible!" ) ;

Les parenth?ses ne sont pas obligatoires.

Chaque processus Unix poss?de son propre rØpertoire courant. Lorsqu un nouveau processus est crØØ, il hØrite ce rØpertoire de son p?re. Si un programme Perl change son rØpertoire, cela n affecte pas le shell qui a lancØ le processus Perl. De mŒme, les processus crØØs par un programme Perl ne peuvent pas modifier le rØpertoire courant de ce programme.

2.11.2. Le globbing

En shell, une simple * permet d accØder la liste des fichiers du rØpertoire courant. De mŒme, [a-m]*.c donne acc?s la liste des fichiers dont le nom commence par une lettre de la premi?re moitiØ de l alphabet et se termine par .c.

Ce genre d action s appelle le globbing. Perl l accepte condition que le globbing pattern soit encadrØ par les signes < et >; exemple:

@liste = </etc/host*>;

# @liste contient la liste des noms de fichiers du répertoire /etc commençant par host

Cela ressemble beaucoup   la lecture d un filehandle:

     dans un contexte scalaire, le glob retourne le nom de fichier matchØ ou undef s il n y en a pas;

• dans un contexte de tableau, le glob retourne la liste des noms de fichier matchØs restants, ou la liste vide s il n y en a pas.

Exemple d utilisation:

while ($nomfic = </etc/host*>)

{ print "Un des fichiers est $nomfic \n " ; }

On peut avoir plusieurs patterns l intØrieur du glob: les listes sont construites sØparØment puis concatØnØes; exemple:

@liste_ceci_cela = <ceci* cela*>;

Bien que globbing et matching fonctionnent de fa on assez similaire, il ne faut pas oublier que la signification des divers caract?res spØciaux est diffØrente: <\.c$> ne permet pas d obtenir la liste des noms de fichier ayant pour extension .c !

L interpolation de variable a lieu dans le glob avant exØcution de celui-ci; exemple:

if (-d "/usr/etc" ) { $ou = "/usr/etc" ; } else

{ $ou = "/etc" ; }

@liste = < $ou/* > ;

Une exception cependant: le pattern <$var> (signifiant qu il faut utiliser la variable $var comme globbing pattern) doit Œtre Øcrit <${var}> pour des raisons que nous verrons plus tard.

2.11.3. Les manipulateurs de rØpertoire

Un manipulateur de rØpertoire est une connexion avec un rØpertoire particulier. Il est toujours ouvert en lecture uniquement: on ne peut pas l utiliser pour changer un nom de fichier ou dØtruire un fichier.

PassØ en param?tre la fonction readdir et ses copines, il permet de manipuler le rØpertoire auquel il est associØ.

Un nom de manipulateur de rØpertoire suit les mŒmes r?gles qu un nom de filehandle: les majuscules sont conseillØes et les mots rØservØs interdits. Le manipulateur de fichier MANIP et le manipulateur de rØpertoire MANIP sont indØpendants.

2.11.4. Ouverture et fermeture d un manipulateur de rØpertoire

La fonction opendir() prend pour param?tres le nouveau manipulateur de rØpertoire et le nom du rØpertoire ouvrir, auquel le manipulateur sera associØ. Cette fonction retourne vrai si le rØpertoire a pu Œtre ouvert, faux sinon. Exemple:

opendir ( ETC, "/etc" ) || die ("opendir n’a pas marché! \n" ) ;

Pour fermer un manipulateur de fichier, on utilise la fonction closedir(); exemple:

closedir(ETC);

Comme close(), closedir() n est pas souvent nØcessaire puisque tous les manipulateurs de rØpertoires sont fermØs automatiquement avant d Œtre rouverts ou en fin d exØcution du programme Perl.

2.11.5. Lecture avec un manipulateur de rØpertoire

Lorsqu un manipulateur de rØpertoire a ØtØ ouvert, la liste des noms de fichiers contenus dans ce rØpertoire peut Œtre lue gr ce la fonction readdir(). Cette fonction prend comme unique argument le manipulateur de rØpertoire et retourne:

•  dans un contexte scalaire, le nom de fichier courant, dans un ordre alØatoire; undef, s il ne reste plus de nom;

•  dans un contexte de tableau, les noms de fichiers restant sous forme de liste dont chaque ØlØment est un nom.

Exemples:

opendir (ETC, "/etc") || die ("opendir n’a pas marché!") ; while ( $nom = readdir(ETC) )   # contexte scalaire

{ print "$nom \n" ; } closedir(ETC) ;

opendir (ETC, "/etc") || die ("opendir n’a pas marché!") ; foreach $nom ( sort readdir(ETC) )

# contexte de tableau, tri { print "$nom \n" ; } closedir(ETC) ;


 

2.12. MANIPULATION DE FICHIERS ET DE REPERTOIRES

2.12.1. Destruction d un fichier

L opØrateur Perl unlink() dØtruit un nom de fichier (qui pourrait avoir plusieurs noms). Lorsque le dernier nom d un fichier est dØtruit, le fichier lui-mŒme est dØtruit. C est l Øquivalent de la commande rm. Comme la plupart du temps un fichier a un nom unique, dØtruire son nom, c est donc le dØtruire. Exemple:

unlink($nomfic);

# le fichier dont le nom est référencé par la variable $nomfic est détruit

L opØrateur unlink() admet une liste de noms de fichier comme param?tre; tous les fichiers dont les noms figurent dans cette liste sont dØtruits. Exemples:

unlink("fic1", "fic2");     # fic1 et fic2 sont détruits unlink(<*.o>);

# tous les fichiers du répertoire courant ayant pour extension

.o sont détruits

unlink() retourne le nombre de fichiers effectivement dØtruits et prend $_ comme param?tre par dØfaut; exemple:

foreach (<*.o>)

{ unlink || print "Impossible de détruire $_ \n " ; }

Tous les fichiers objet du rØpertoire courant sont dØtruits successivement; un message permet de conna tre les noms des fichiers ne pouvant Œtre dØtruits.

2.12.2. Renommage d un fichier

Cette opØration est effectuØe avec l opØrateur rename(), comme suit:

rename ($old, $new); rename ("fic", "fic1");

# le fichier fic est renommé fic1.

Cet opØrateur retourne la valeur vrai si le renommage a pu Œtre effectuØ.

Si la commande shell mv permet le raccourci mv fichier un_répertoire, la commande rename() ne le permet pas; il faut Øcrire:

rename("fichier", "un_répertoire/fichier");

2.12.3. CrØation de liens sur un fichier

Comme si un nom pour un fichier ne suffisait pas, parfois on en veut deux ou trois ou une douzaine. Cette opØration de crØation de plusieurs noms pour un mŒme fichier s appelle le linking. Il y a deux sortes de linking: Øtablissement de lien physique et Øtablissement de lien symbolique.

Liens physique et symbolique

Un lien physique sur un fichier n’est pas distinguable du nom du fichier.

Le noyau Unix met jour un compteur qui est le nombre de liens physiques se rapportant un fichier. Si un lien est dØtruit, ce compteur est dØcrØmentØ; si un nouveau lien est crØØ, le compteur est incrØmentØ. Lorsque le fichier est crØØ, le compteur prend la valeur 1.

Chaque lien physique sur un fichier doit se trouver sur la mŒme partition montØe.

On ne peut crØer qu’un seul lien physique sur un rØpertoire: celui qui est Øtabli lors de la crØation du rØpertoire. Toute tentative d’en crØer un deuxi?me est fatale. C’est pour protØger la hiØrarchie Unix des fichiers.

Un lien symbolique est une forme spØciale de fichier qui contient comme donnØes un chemin d’acc?s. Lorsque ce fichier est ouvert, le noyau Unix consid?re son contenu comme un aiguillage supplØmentaire pour le chemin d’acc?s; il continue alors son avance dans la hiØrarchie.

Un lien symbolique peut Œtre crØØ sur un rØpertoire.

Le contenu d’un lien symbolique n’a pas besoin d’Œtre un fichier ou un rØpertoire existant. Il peut mŒme se trouver sur une autre partition montØe. Un lien symbolique peut pointer sur un autre lien symbolique.

Un lien physique Øvite la perte du contenu d’un fichier (puisqu’il est en fait un nom du fichier). Un lien symbolique ne peut empŒcher cette perte.

Il faut Œtre autorisØ en Øcriture dans le rØpertoire oø l’on crØe ces deux sortes de liens, sans pour autant Œtre autorisØ ouvrir le fichier sur lequel sont crØØs les liens. Il faut pouvoir appliquer stat() au fichier sur lequel on veut crØer un lien physique; ceci n’est pas nØcessaire pour crØer un lien symbolique.

CrØation de liens physique et symbolique avec Perl

L opØrateur link() permet de crØer des liens physiques. Il prend comme param?tres le vieux nom du fichier et le nouvel alias pour ce fichier. Il retourne vrai si le lien a pu Œtre crØØ. Comme avec rename(), il faut prØciser dans son entier le nouveau nom de fichier (et pas seulement le rØpertoire). Exemple:

link("fic1", "fichier_1") || die("Impossible de créer un lien physique entre fic1 et fichier_1 \n");

Pour un lien physique, le vieux nom ne peut pas Œtre celui d’un rØpertoire et le nouvel alias doit Œtre sur la mŒme partition montØe.

Sur les syst?mes admettant les liens symboliques, l opØrateur symlink() permet de crØer cette sorte de lien. Il prend comme param?tres le vieux nom du fichier ou du rØpertoire et le nouvel alias pour ce fichier ou ce rØpertoire. Le fichier ou le rØpertoire n’a pas besoin d’exister pour qu’il soit possible de crØer un lien symbolique sur lui. Exemple:

symlink("fic2", "fichier_2") || die("Impossible de créer un lien symbolique entre fic2 et fichier_2 \n");

L’opØrateur readlink() permet de savoir ce sur quoi le lien symbolique passØ en param?tre pointe. Exemple:

if ($nom = readlink("fichier_2"))

{ print "fichier_2 pointe sur $nom \n" ; }

# $nom contient fic2

readlink() retourne undef si le lien testØ n’existe pas, ne peut Œtre lu ou n’est pas un lien symbolique.

2.12.4. CrØation et destruction d un rØpertoire

L opØrateur mkdir() permet de crØer un nouveau rØpertoire dont le nom et les droits lui sont passØs en param?tres. Les droits sont spØcifiØs par un entier (le mode) interprØtØ comme un format de droits internes. La page man chmod(2) prØcise les droits internes. Si vous Œtes pressØs, le mode 0777 permet de tout faire pratiquement. Exemple:

mkdir("rep", 0777);

# création du répertoire rep avec le mode 0777

L opØrateur rmdir() permet de supprimer un rØpertoire vide; exemple:

             rmdir("rep");         # destruction du répertoire rep

2.12.5. Modification de droits

Les droits sur un fichier ou un rØpertoire indiquent qui a le droit de faire quoi avec ce fichier ou ce rØpertoire. L opØrateur Perl chmod() permet de changer ces droits. Il prend comme param?tres un entier, le mode, et une liste de noms de fichiers, et tente de modifier les droits de tous ces fichiers avec le mode indiquØ. Exemple:

chmod(0666, "fic1", "fic2");

Avec le mode 0666, fic1 et fic2 deviennent accessibles en lecture et en Øcriture pour tout le monde (utilisateur, groupe et autres). chmod() retourne le nombre de fichiers dont il a rØussi modifier les droits.

2.12.6. Modification de la propriØtØ

Tout fichier ou rØpertoire a un propriØtaire et un groupe dans le syst?me de fichiers. Le propriØtaire et le groupe dØterminent qui les droits de propriØtØ et de groupe s appliquent. Ils sont dØterminØs au moment de la crØation du fichier, mais on peut les changer.

L opØrateur chown() prend comme param?tres un UID, un GID et une liste de noms de fichiers, et tente de changer la propriØtØ de chacun des fichiers spØcifiØs. Il retourne le nombre de fichiers dont il a rØussi modifier la propriØtØ.

Remarquez qu on change le propriØtaire et le groupe en mŒme temps.

UID et GID doivent Œtre des valeurs numØriques, et non les noms symboliques correspondants. Exemple:

chown(1234, 35, "fic1", "fic2"); fic1 et fic2 appartiennent maintenant l utilisateur d UID 1234 et au groupe de GID 35.

2.12.7. Modification des timestamps

Trois timestamps sont associØs un fichier. Nous en avons parlØ bri?vement au paragraphe 2.9.4. Il s agit des ges de derni?re modification, de dernier acc?s d un fichier et de derni?re modification de l inode de ce fichier.

L opØrateur utime() permet de donner aux deux premiers timestamps des valeurs arbitraires. Modifier ces deux valeurs modifie automatiquement la troisi?me et lui donne pour valeur le temps courant. Donc, pas besoin d opØrateur spØcial pour a!

utime() prend comme param?tres les ges en secondes du dernier acc?s et de la derni?re modification, et une liste de noms de fichiers; il retourne le nombre de fichiers pour lesquels l opØration a rØussi. Exemple:

$atime = $mtime = 700 000 000; utime($atime, $mtime, "fic1", "fic2");

Les temps sont mesurØs en temps interne Unix; ce sont des valeurs enti?res de secondes, comptØes partir du 01/01/70 G.M.T.


 

2.13. LA GESTION DE PROCESSUS

2.13.1. L utilisation de system()

Perl peut lancer de nouveaux processus. La fa on la plus simple de le faire est d’utiliser l’opØrateur system(). Cet opØrateur donne en fait la cha ne qu’on lui passe en param?tre un shell /bin/sh qui l’exØcute comme une commande. Quand l’exØcution est terminØe, system() retourne 0 si tout s’est bien passØ. Exemple:

system("date"); # permet d'obtenir la date

L opØrateur system() hØrite du processus Perl les fichiers d entrØe, de sortie et d erreur standards. Le rØsultat de la commande shell sera donc dans STDOUT. Cependant il peut Œtre redirigØ; exemple:

system("date > ficdate") &&

die "Impossible de créer ficdate \n"; # permet d'obtenir la date dans le fichier ficdate et de vérifier la valeur de retour de system()

system() peut prendre comme param?tre tout ce que /bin/sh accepte d exØcuter: plusieurs commandes sØparØes par des points virgules, des retours la ligne, des lancements en arri?re plan Exemple:

system("(date ; who) > $fic & ") ;

# lancement de date et who en arrière plan avec sortie dans le ficher référencé par la variable Perl $fic

Perl offre la possibilitØ de consulter et de modifier les variables d environnement gr ce au tableau associatif %ENV, dont chaque ØlØment est une paire (nom de variable d environnement, valeur de cette variable). Voici un exemple permettant d afficher toutes les variables d environnement et leur valeur:

foreach $key (sort keys %ENV) { print "$key = $ENV{$key} \n" ; }

L opØrateur system() admet Øgalement une liste de param?tres. Plut t que de donner cette liste au shell, Perl interpr?te le premier ØlØment de cette liste comme la commande exØcuter avec pour param?tres les ØlØments suivants de la liste. Exemple:

system "grep 'seb' fic_speinf"; system "grep", "seb", "fic_speinf";

# idem mais avec une liste

L utilisation d une liste plut t que d une cha ne Øconomise un processus shell.

2.13.2. L utilisation des backquotes

Une autre fa on de lancer un processus est d encadrer une ligne de commande /bin/sh avec des backquotes. La commande est exØcutØe et le rØsultat est rØcupØrØ sur la sortie standard. Il devient la valeur de la cha ne entre backquotes; exemple:

$date = "on est aujourd’hui".`date`;

# $date contient maintenant la concaténation de la chaîne de caractères et du résultat de la commande shell date

Si la commande entre backquotes est utilisØe dans un contexte de tableau, le rØsultat est une liste de cha nes, chacune Øtant une ligne (terminØe par un newline) de la sortie de la commande. Pour l exemple ci-dessus, nous n aurions eu qu un ØlØment, puisqu une seule ligne est gØnØrØe. Autre exemple:

foreach (`who`)

{ ($qui, $ou, $quand) = / (\S+) \s+ (\S+) \s+ (.*)/ ;    print "$qui sur $ou à $quand \n" ; }

 2.13.3. Utilisation de processus comme filehandles

Une autre mØthode pour lancer un processus est de crØer un processus qui ressemble un manipulateur de fichier. Comme les filehandles sont ouverts soit en Øcriture soit en lecture, il est possible de crØer un processus-filehandle qui peut capturer la sortie ou fournir l entrØe du processus; exemple:

open (PROC, "who | " ) ;

@who = <PROC>;

La barre verticale droite de who indique Perl qu il n est pas en train d ouvrir un filehandle mais plut t de lancer une commande. Comme la barre est droite de la commande, le filehandle est ouvert en lecture, ce qui signifie que la sortie de who doit Œtre capturØe. La deuxi?me ligne permet de ranger le rØsultat de la commande dans un tableau dont chaque ØlØment est une ligne du who.

De mŒme, pour lancer une commande avec des param?tres, on peut ouvrir un processusfilehandle en Øcriture en mettant la barre verticale gauche de la commande; exemple:

open (LPR, " | lpr -Pslatewriter" ) ; print LPR @report ; close(LPR) ;

Apr?s avoir ouvert LPR, on y a Øcrit des donnØes puis on l a fermØ. Ouvrir un processusfilehandle permet la commande de s exØcuter en parall?le avec le programme Perl. close() force ce programme attendre que le processus meurt. Si on ne ferme pas le processusfilehandle, le processus peut continuer de s exØcuter mŒme apr?s terminaison du programme

Perl.

2.13.4. L utilisation de fork

Une autre mØthode pour lancer un nouveau processus est de cloner le processus Perl avec la primitive Unix fork.

L opØrateur Perl fork fait simplement ce que l’appel syst?me fork exØcute: il crØe un processus fils, qui partage avec son p?re le mŒme code exØcutable, les mŒmes variables et mŒme les mŒmes fichiers ouverts. Pour distinguer les deux processus, la valeur de retour de fork est 0 pour le fils et une valeur non nulle pour le p?re. Exemple:

if (fork)

{ # je suis le père } else

{ # je suis le fils }

Perl dispose Øgalement des opØrateurs wait, exec et exit. En fait, il se contente de passer les appels ces opØrateurs aux appels syst?me d Unix.

exec est comme l opØrateur system, si ce n est qu au lieu de crØer un nouveau processus pour exØcuter une commande shell, il remplace le processus courant par le shell. Pour obtenir quelque chose d Øquivalent un appel system, il faut combiner fork et exec; exemple:

# méthode 1 system "date" ; # méthode 2 unless(fork)

{  # fork a retourné 0,

   # je suis donc le processus fils et j’exécute:    exec ("date") ; }

             wait;       # le père attend que le fils meurt

wait permet de faire attendre le p?re jusqu ce que le fils meurt.

Enfin, l opØrateur exit() permet de sortir immØdiatement du processus Perl courant. Cet opØrateur peut prendre un param?tre optionnel qui est un entier indiquant la mani?re dont on est sorti. Par dØfaut, on sort avec la valeur 0, qui indique que tout s est bien passØ. Exemple:

unless(fork)

{ # je suis le processus fils    unlink </tmp/bedrock.*> ;

  # destruction de tous ces fichiers

                exit();                  # le fils arrête de s’exécuter ici

}

# le père continue de s’exécuter ici

Sans le exit, le processus fils continue d exØcuter le programme Perl ( la ligne 'le père continue de s’exécuter ici').

2.13.5. RØsumØ des opØrations sur les processus

Le tableau suivant rØsume les diffØrentes fa ons de crØer un processus avec Perl:

OpØration

EntrØe standard

Sortie standard

Erreur standard

Attendu?

system()

hØritØe du programme

hØritØe du programme

hØritØe du programme

oui

backquotes

hØritØe du programme

capturØe en tant que cha ne

hØritØe du programme

oui

open() pour un filehandle en lecture

connectØe au

filehandle

hØritØe du programme

hØritØe du programme

au moment du close()

open() pour un filehandle en Øcriture

hØritØe du programme

connectØe au

filehandle

hØritØe du programme

au moment du close()

fork, exec, wait

choix de

l utilisateur

choix de

l utilisateur

choix de

l utilisateur

choix de

l utilisateur

La plus simple fa on de crØer un processus est d appeler system(). STDIN, STDOUT et STDERR sont inchangØes. Avec les backquotes, la sortie est capturØe sous forme d une cha ne de caract?res; STDIN et STDERR sont inchangØes. Avec ces deux mØthodes, le programme Perl attend que le processus meurt pour continuer son exØcution.

Pour une exØcution en parall?le, l ouverture d une commande en tant que filehandle est une mØthode simple.

La mØthode la plus souple est d utiliser les opØrateurs fork, wait et exec qui sont directement reliØs aux appels syst?me du mŒme nom. On peut alors choisir entre les exØcutions sØquentielle et parall?le.

2.13.6. Envoi et rØception de signaux

Une mØthode de communication interprocessus sous Unix est l envoi et la rØception de signaux. Un signal est un message de 1 bit envoyØ un processus par un autre processus ou par le noyau Unix.

La rØponse un signal s appelle action du signal. Certains signaux ont pour action par dØfaut de tuer ou de suspendre le processus. D autres sont compl?tement ignorØs par dØfaut.

Quand un processus Perl capte un signal, une subroutine de votre choix est lancØe automatiquement, interrompant temporairement ce qui Øtait en train de s exØcuter. Lorsque la subroutine a ØtØ exØcutØe, le contexte est restituØ, comme s il ne s Øtait rien passØ (sauf si la subroutine a exØcutØ des instructions).

En gØnØral, une telle subroutine fait l une de ces deux choses:

•  apr?s avoir effectuer des instructions de nettoyage, elle arrŒte l exØcution du programme;

•  elle positionne un flag (par exemple une variable globale) que le programme consulte rØguli?rement.

Les noms des signaux sont disponibles dans la page man de l’appel syst?me signal. Pour associer une subroutine de traitement de signal un signal, on utilise le tableau associatif %SIG. Ce tableau a pour clØs les signaux. Pour associer la subroutine &traite_sigint au signal SIGINT, il suffit d Øcrire:

$SIG{'INT'} = 'traite_sigint';

sub traite_sigint

{ $sigint_flag = 1 ; # positionnement d’un flag }

Cette subroutine positionne donc une variable globale et se termine tout de suite apr?s. L exØcution du programme reprend l oø elle s Øtait interrompue.

On peut Øgalement donner des valeurs spØciales aux signaux:

•  ’DEFAULT’: associe au signal son action par dØfaut;

•  ’IGNORE’: permet d ignorer le signal.

Un signal peut Œtre gØnØrØ par l utilisateur lorsqu il frappe certains caract?res. Un processus peut Øgalement gØnØrer un signal, gr ce l opØrateur kill(). Cet opØrateur prend comme param?tres un nom ou un numØro de signal et les numØros des processus auxquels ce signal doit Œtre envoyØ. Exemple:

kill ( 2, 234, 237);

Le signal 2, SIGINT, est envoyØ aux processus 234 et 237.

2.14. AUTRES TRANSFORMATIONS SUR LES DONNEES

2.14.1. Recherche d une sous-cha ne

L opØrateur index() permet de retrouver une sous-cha ne dans une cha ne plus longue. Exemple:

$x = index($chaine, $ss_chaine);

Cet opØrateur rep?re la premi?re occurrence de la sous-cha ne dans la cha ne et renvoie un entier qui est la position du premier caract?re de la sous-cha ne dans la cha ne; exemples:

$pos = index ("coucou", "co");    # $pos = 0 $pos = index ("coucou", "ouc");     # $pos = 1

$ss_chaine = "ba";

$pos = index ("coucou", $ss_chaine);

# $pos = -1 (on n’a pas trouvé "ba" dans "coucou")

Les opØrandes d index() peuvent Œtre des cha nes, des variables scalaires contenant des cha nes ou des expressions ayant pour valeur une cha ne.

On peut donner un troisi?me param?tre index() afin de trouver les autres occurrences de la sous-cha ne l intØrieur de la cha ne. La recherche se fera droite de la position indiquØe par ce param?tre. Exemples:

$pos = index ("coucou", "co", 1);

# $pos = 3, deuxième occurrence de "co"

$pos = index ("coucou","co",4);

# $pos=-1, "co" n’apparaît plus après la position 4

On peut effectuer la recherche en partant de la droite; pour cela il existe l opØrateur rindex(). La position retournØe est toujours compter partir de la gauche, mais elle concerne la premi?re occurrence de la sous-cha ne en partant de la droite. Exemples:

$pos = rindex ("coucou", "co");

# $pos=3, première occurrence de "co" en partant de la droite

             $pos = rindex ("bateau", "ba");             # $pos = 0

             $pos = rindex ("hello world", "o", 3);      # $pos = -1

             $pos = rindex ("hello world", "o", 6);      # $pos = 4

Comme le montrent les deux derniers exemples, rindex() peut Øgalement prendre un troisi?me param?tre qui est la position gauche de laquelle la recherche est effectuØe.

2.14.2. Extraction et remplacement d une sous-cha ne

Extraire une cha ne de caract?res peut se faire gr ce aux expressions rØguli?res. On peut Øgalement utiliser l opØrateur substr(), qui a pour syntaxe:

$s = substr($chaine, $pos, $long);

$s re oit la sous-cha ne extraite de $chaine partir de la position $pos et de longueur $long; exemples:

$s = substr("hello world", 3, 4);

# $s =  "lo w"

$s = substr("hello world", 2, 100);

# $s =  "llo world"

$s = substr("hello world", -3, 3);

# $s =  "rld"

$s = substr("hello world", -3, 1);

# $s =  "r"

Une valeur nØgative de la position indique la position en partant de la fin du mot. Attention, le dernier caract?re est accØdØ par la position -1, alors que le premier caract?re est accØdØ par la position 0.

Si $pos est un nombre nØgatif plus grand en valeur absolue que la longueur de la cha ne, alors la recherche est effectuØe partir de la position 0. Si $pos est un nombre positif plus grand que la longueur de la cha ne, alors la cha ne vide "" est retournØe. Si on n indique pas de longueur, substr() retourne tout ce qui se trouve droite de $pos, jusqu la fin de la cha ne.

Si le premier param?tre de substr() est une variable, alors substr() peut figurer gauche d une affectation; exemple:

$chaine = "hello cricri"; substr($chaine, 0, 5) = "howdy";

# $chaine = "howdy cricri"

Mais la sous-cha ne de remplacement n a pas forcØment la mŒme longueur que celle qui dispara t. La cha ne finale est automatiquement allongØe ou raccourcie; exemple:

$chaine = "hello cricri"; substr($chaine, 0, 5) = "hi";      # $chaine = "hi cricri" substr($chaine, -6, 6) = "sebastien";

# $chaine = "hello sebastien"

2.14.3. Associer des formats aux donnØes avec sprintf()

printf() permet d afficher une liste de valeurs avec des formats. sprintf() fait la mŒme chose, mais retourne le rØsultat dans une cha ne de caract?res; exemple:

$var = sprintf("X%05d", $y);

2.14.4. Un tri performant

Nous avons dØj vu que l opØrateur sort appliquØ une liste permet de la trier suivant l ordre ASCII croissant. Et si on veut rØaliser d autres tris, par exemple un tri numØrique? Eh bien, en fait sort est un opØrateur gØnØral; il suffit de dØfinir une subroutine de comparaison de deux ØlØments.

Cette subroutine de comparaison est dØfinie comme une subroutine ordinaire et est appelØe de fa on rØpØtitive, jusqu ce que la liste soit triØe.

Pour gagner en vitesse d exØcution, les deux ØlØments comparØs ne sont pas passØs la subroutine sous forme de tableau, mais en tant que valeurs des variables globales $a et $b. La subroutine retourne:

•   un nombre nØgatif si $a «est infØrieure            » $b

•   0 si $a «Øgale» $b

•   un nombre positif si $a «est supØrieure » $b.

infØrieur, supØrieur et Øgal ayant le sens qu implique la comparaison effectuØe. La subroutine suivante permet d effectuer un tri numØrique:

sub by_number { if ($a < $b)    { -1; }    elsif ($a > $b)    { 1; }    elsif ($a == $b)

   { 0; }

}

Comment l utiliser? Prenons par exemple la liste suivante:

@liste = ( 1, 2, 4, 8, 16, 32, 48, 64, 128, 256);

Si on utilise sort comme on le fait d habitude, les ØlØments de la liste @liste seront ordonnØs comme des cha nes de caract?res:

@mauvaise_liste = sort @liste;

# @mauvaise_liste = (1, 128, 2, 256, 32, 4, 48, 64, 8)

Pour un tri numØrique, il faut utiliser notre subroutine de comparaison comme suit:

@bonne_liste = sort by_number @mauvaise_liste;

# @bonne_liste = (1, 2, 4, 8, 16, 32, 48, 64, 128, 256)

Remarquez que le & n est pas obligatoire: Perl reconna t que la cha ne entre sort et la liste est la subroutine de comparaison.

Ce genre de comparaison renvoyant -1, 0 ou 1 est si frØquent que Perl dispose de l opØrateur vaisseau_spatial, notØ <=>. Si on l utilise, notre subroutine s Øcrit alors tout simplement:

sub by_number

{ $a <=> $b ; }

On peut aller encore plus loin en rempla ant le nom de la subroutine par l instruction qu elle exØcute:

@bonne_liste = sort { $a <=> $b } @mauvaise_liste;

<=>, opØrateur pour la comparaison numØrique, a pour Øquivalent cmp pour la comparaison des cha nes de caract?res. Une fa on de trier une liste par ordre ASCII croissant (sort classique) est d Øcrire:

@resultat = sort { $a cmp $b } @liste;

Ce nouvel opØrateur peut sembler inutile premi?re vue. Pourtant il permet de garantir que la liste triØe aura toujours les mŒmes ØlØments la mŒme place. En effet, si des ØlØments de la liste sont Øgaux, alors on n obtiendra pas forcØment la mŒme liste apr?s chaque tri.

Supposons par exemple vouloir obtenir une liste des logins et des vrais noms des utilisateurs ordonnØe par les noms d utilisateur. Si ces valeurs se trouvent dans le tableau associatif %nom indexØ par les logins, il suffit d Øcrire:

@cles_triees = sort by_names keys(%nom);

sub by_names

{ ($nom{$a} cmp $nom{$b}) || ($a cmp $b) ; }

foreach @cles_triees

{ print "$_ a pour vrai nom $nom{$_} \n" ; }

Si deux noms d utilisateurs sont identiques, on compare leurs logins, ce qui Øvite d avoir l affichage un coup "grossior a pour vrai nom grossiord"

"seb a pour vrai nom grossiord"

et une autre fois         "seb a pour vrai nom grossiord"

"grossior a pour vrai nom grossiord"

2.14.5. TranslitØration

Si l on veut remplacer un caract?re d une cha ne par un autre ou supprimer toute occurrence d un caract?re, on peut utiliser l opØrateur s///. Mais si l on veut remplacer tous les a par des b et tous les b par des a? Deux appels successifs s/// ne feront pas ce qu on attend puisque le deuxi?me annulera l effet du premier.

Perl dispose donc de l opØrateur tr/// qui est tr?s proche de la commande shell tr. Exemple:

tr /ab/ba/;

Cet opØrateur prend deux arguments: la vieille cha ne et la nouvelle cha ne. Ils agissent comme les deux arguments de s///. tr/// modifie le contenu de la variable $_; il cherche les caract?res de la vieille cha ne et les remplace par ceux de la nouvelle cha ne. Exemples:

$_ = "coucou! ca va?" ; tr /cau/fid/ ; # $_ contient maintenant "fodfod! fi vi?" tr /a-c/A-C/ ; # $_ contient maintenant "CouCou! CA vA?"

Si la nouvelle cha ne est plus courte que la vieille, le dernier caract?re de la nouvelle cha ne est rØpØtØ autant de fois que nØcessaire pour que la cha ne oø s effectue la recherche conserve la mŒme longueur; exemple:

$_ = "coucou! ca va?" ;

             tr /a-z/x/ ;           # $_ contient maintenant "xxxxxx! xx xx?"

Pour Øviter cela, il suffit d ajouter le caract?re d la fin de l appel tr///; exemple:

             tr /a-z/A-C/d ;       # $_ contient maintenant "CC! CA A?"

Tout caract?re de la vieille cha ne auquel ne correspond pas une valeur dans la nouvelle cha ne est supprimØ.

Si la nouvelle liste est vide et qu il n y pas d option d, la nouvelle liste est alors la mŒme que la vieille liste. Cela peut para tre idiot. Cependant tr/// retourne alors le nombre de caract?res matchØs par la vieille cha ne.

Exemples:

$_ = "coucou! ca va?" ;

             $nb = tr /a-z// ;           # $_ n’a pas changé mais $nb = 10

             $nb = tr /a-z/A-Z/ ;        # $_ est en majuscule et $nb = 10

Si on place un c en fin d appel tr///, on prend comme vieille cha ne le complØmentaire de la vieille cha ne dans l ensemble des 256 caract?res alphanumØriques; exemples:

$_ = "coucou! ca va?" ;

$nb = tr /a-z//c; # $_ n’a pas changé mais $nb = 3 $nb = tr /a-z/_/c ;  # $_ = "coucou__ca_va_" et $nb = 3 tr /a-z//cd ;

# $_ contient maintenant "coucoucava"

Les options peuvent Œtre combinØes, comme le montre ce dernier exemple.

La derni?re option de tr/// est s, qui a pour effet de substituer les copies successives d une mŒme lettre de la nouvelle cha ne par une unique copie; un exemple est plus parlant!

$_ = "aaabbbcccdefghi";

             tr /defghi/abcddd/s ;       #     $_     contient     maintenant

"aaabbbcccabcd"

$_ = "cricri et seb, hugo et xav";

             tr /a-z/X/s ;               # $_ contient maintenant "X X X, X X

X"

$_ = "cricri et seb, hugo et xav";

             tr /a-z/_/cs ;              #     $_     contient     maintenant

"cricri_seb_hugo_xav"

Comme s///, tr/// peut Œtre appliquØ une autre cha ne que $_ en utilisant l opØrateur =~; exemple:

$chaine = "cricri et seb, hugo et xav";

$chaine =~ tr /a-z/_/cs ;

# $chaine contient maintenant "cricri_seb_hugo_xav"

2.15. ACCES AUX DONNEES SYSTEME

2.15.1. Pour rØcupØrer des informations sur les mots de passe et les groupes

Les informations que poss?de le syst?me sur votre nom d’utilisateur et votre UID sont publiques. En fait, pratiquement tout sauf votre mot de passe est disponible. Il suffit d’accØder le fichier /etc/passwd. Ce fichier a un format particulier:

name:passwd:uid:gid:gcos:dir:shell

Les champs sont dØfinis comme suit:

name

le login de l’utilisateur

passwd

le mot de passe cryptØ de l’utilisateur

uid

l’identificateur d’utilisateur (0 pour le root, un nombre non nul pour les autres utilisateurs)

gid

l’identificateur de groupe par dØfaut

gcos

le champ GCOS, qui contient en gØnØral le nom de l’utilisateur, une virgule et d’autres informations

dir

le rØpertoire racine de l utilisateur

shell

le shell lancØ au moment du login

Perl dispose de l’opØrateur getpwnam(), qui prend comme unique argument un nom d’utilisateur et retourne la ligne du fichier /etc/passwd correspondante, dØcomposØe dans un tableau:

($name,$passwd,$uid,gid,$quota,$comment,$gcos,$dir,$shell)

$quota est toujours vide; $comment et $gcos contiennent tous les deux le champ GCOS.

Si on utilise l’opØrateur getpwuid() en lui passant le UID de l’utilisateur, on obtient le mŒme tableau.

getpwuid() et getpwnam() sont des opØrateurs permettant d’accØder une ligne de /etc/passwd gr ce une clØ: le UID ou le nom de l’utilisateur. Si on dØsire maintenant un acc?s sØquentiel /etc/passwd, Perl propose les opØrateurs setpwent(), getpwent() et endpwent(). Ces opØrateurs passent en revue toutes les lignes de /etc/passwd. setpwent() initialise le parcours au dØbut du fichier. Chaque appel getpwent() retourne la ligne courante du fichier; lorsqu’il n’y a plus de ligne lire, il retourne la liste vide. Un appel endpwent() permet de libØrer les ressources utilisØes pour scanner /etc/passwd. Exemple:

setpwent; # initialise le parcours while (@liste = getpwent )

{ # récupère la ligne courante

   ($login, $home) = @liste[0, 7]; # création d'un tableau associatif dont la clé est le login    print "Le répertoire racine de $login est $home";

}

endpwent; # libération des ressources

En gØnØral, on utilise getpwuid() et getpwnam() pour accØder un petit nombre d’informations. Si on souhaite accØder plus d’informations, il vaut mieux utiliser setpwent(), getpwent() et endpwent().

Pour accØder le fichier /etc/group, il existe de mŒme les opØrateurs setgrent(), getgrent() et endgrent() pour un acc?s sØquentiel, et getgrgid() et getgrnam() pour un acc?s par le GID ou le nom du groupe.

Un appel getgrent() retourne le tableau:

($name, $passwd, $gid, $members)

Ces quatre valeurs correspondent exactement aux quatre champs du fichier /etc/group.

2.15.2. Manipulation de donnØes binaires

L’opØrateur Perl pack() fonctionne un peu comme sprintf(). Il prend comme param?tre une cha ne de contr le de formats et une liste de valeurs, ne faisant plus qu’une seule cha ne de cette liste. Cependant, il est orientØ vers la crØation de structures de donnØes binaires. Exemple:

pack ("CCCC", 140, 186, 65, 25);

Une cha ne est crØØe, qui contient quatre octets dont les valeurs sont celles des quatre entiers. Le format C permet de transformer un petit entier (une valeur de caract?re non signØe) en un octet.

Le format l permet de gØnØrer une valeur long signØe. Il dØpend cependant de la machine; en gØnØral, c’est un nombre codØ sur quatre octets. Exemple:

$buf1 = pack("l", 0x41424344);

$buf2 = pack("ll", 0x41424344, 0x45464748);

$buf1 contient ABCD ou DCBA (cela dØpend de la machine), et $buf2 contient ABCDEFGH ou DCBAHGFE.

La liste des diffØrents formats pour pack() est disponible dans la page man de Perl.

Pour rØaliser l’opØration contraire de l’opØration prØcØdente, on utilise l’opØrateur unpack(), qui prend comme param?tres une cha ne de format et une cha ne de donnØes, et retourne une liste de valeurs, images mØmoire de la cha ne de donnØes. Exemple:

($val1, $val2) = unpack("ll", "ABCDEFGH");

On obtient $val1=0x61626364 ou 0x64636261, $val2=0x65666768 ou 0x68676665. Les espaces ne sont pas pris en compte dans la cha ne de format. Un nombre dans cette cha ne permet en gØnØral de rØpØter le format prØcØdent autant de fois; exemples:

pack ("C4", 140, 186, 65, 25);

# équivaut à pack ("CCCC", 140, 186, 65, 25); pack ("C2C2", 140, 186, 65, 25); # idem

Un format peut Øgalement Œtre suivi d’une *, ce qui permet de l’appliquer au reste de la liste ou au reste de l’image mØmoire. Exemple:

pack ("C*", 140, 186, 65, 25);

# équivaut à pack ("CCCC", 140, 186, 65, 25);

@valeurs = unpack("C*", "bonjour tout le monde! \n");

Ce dernier exemple gØn?re une liste de 14 ØlØments (nombres), chacun Øtant associØ un caract?re de la cha ne.

2.15.3. Pour rØcupØrer des informations sur le rØseau

Perl permet la programmation rØseau d’une fa on tr?s proche de celle du C. En fait, la plupart des routines Perl permettant d’accØder au rØseau ont les mŒmes noms et param?tres que leurs Øquivalents en C.

En gØnØral, on a besoin de trouver l’adresse d’une machine du rØseau dont on conna t le nom, et vice versa. La routine Perl gethostbyname() permet de trouver l’adresse partir du nom; exemple:

( $name, $aliases, $addrtype, $length, @addrs) =

 gethostbyname($name);

Le param?tre de cette routine est donc un hostname, par exemple . Le rØsultat est une liste dont le nombre d’ØlØments dØpend du nombre d’adresses associØes au nom. Si le hostname n’est pas valide, la liste vide est retournØe.

L’information importante est le tableau @addrs; chacun de ses ØlØments est une adresse IP, passØe Perl en tant que cha ne de 4 caract?res. Si on souhaite afficher le rØsultat, il faudra convertir cette cha ne avec unpack(). Exemple:

($addr) = (gethostbyname(""))[4]; print "L'adresse de Slate est ", join(".", unpack("C4", $addr)), "\n";

unpack() prend 4 caract?res et retourne 4 nombres, qui, recollØs, constitue une adresse IP comme nous avons l’habitude de les voir.

2.15.4. Pour rØcupØrer d autres informations

On peut Øgalement rØcupØrer des informations sur une machine h te partir de son adresse, et des informations sur le rØseau partir de son adresse et de son nom. Il existe aussi des routines permettant d’accØder aux protocoles et la liste des services du rØseau. Elles fonctionnent comme celles du C.

Voir le guide de rØfØrence de Perl en annexe.

2.15.5. Un exemple de programmation rØseau avec Perl

•  Le mod?le socket

1.    Le processus serveur crØe une socket gØnØrique avec socket().

2.    Le serveur lie la socket  une adresse convenue avec bind().

Le serveur fait savoir au syst?me que tout est prŒt pour l Øtablissement de connexions avec listen().

3.    Le serveur attend la premi?re connexion avec accept().

4.    Le processus client crØe une socket gØnØrique avec socket().

5.    Le client lie la socket     une adresse sØlectionnØe par le syst?me avec bind().

6.    Une fois liØ, le client connecte sa socket celle du serveur avec connect(), en utilisant l adresse convenue. Cela Øtablie la connexion.

7.    Le serveur est averti de cette nouvelle connexion. En gØnØral, il fait alors appel fork pour crØer un processus fils qui sera en charge de cette nouvelle connexion, le p?re restant en attente de la prochaine connexion.

8.    Le processus fils lit les donnØes partir de la socket envoyØe par le client; il y Øcrit Øgalement des donnØes qui peuvent ensuite Œtre lues par le client. Ces E/S sont traitØes comme s il s agissait de filehandles.

9.    Lorsque le fils et le client ont terminØ leur communication, ils ferment le filehandle,fermant ainsi le connexion.

•  Un exemple de client

 Ce client est connectØ une adresse prØcise (le standard «daytime») sur une machine h te prØcise (local host) et affiche tout ce que le port gØn?re en sortie:

 require '';  $sockaddr = 'S n a4 x8';  chop($hostname = `hostname`);

 ($name, $aliases, $proto) = getprotobyname('tcp');

 ($name, $aliases, $port) = getservbyname('daytime', 'tcp');

 ($name, $aliases, $type, $len, $thisaddr) =

                                                                                       gethostbyname($hostname);

 $thisport = pack($sockaddr, &AF_INET, 0, $thisaddr);

 $thatport = pack($sockaddr, &AF_INET, $port, $thisaddr);

 socket(S, &PF_INET, &SOCK_STREAM, $proto) ||

                                                    die("Impossible de créer la socket. ");

 bind(S, $thisport) || die("Impossible de lier la socket. ");  connect(S, $thatport) || die("Connexion impossible. ");  while (<S>)  { print; }

 exit 0;

Un exemple de serveur

Ce serveur crØe une socket l adresse 4242 sur la machine courante. Celui qui se connecte sur ce port re oit un g teau de la chance. Chaque g teau n est utilisØ qu une fois (de fa on alØatoire) jusqu ce que tous les g teaux soient mangØs. La base de g teaux est alors rØamorcØe.

Ce serveur peut Œtre utilisØ avec le client ci-dessus condition de remplacer la ligne d affectation de $port par l instruction $port = 4242. On peut aussi Øcrire telnet localhost 4242, pour observer la sortie.

 require '';  $sockaddr = 'S n a4 x8';  chop($hostname = `hostname`);

 ($name, $aliases, $proto) = getprotobyname('tcp');

 $port = 4242;

 $thisport = pack($sockaddr, &AF_INET, $port, "\0\0\0\0");

 socket(S, &PF_INET, &SOCK_STREAM, $proto) ||

                                                               die("Impossible de créer la socket. ");

 bind(S, $thisport) || die("Impossible de lier la socket. ");  listen(S, 5) || die("Impossible d’ecouter. ");  for ( ; ; )

 { accept(NS, S) || die("Impossible d’accepter le socket. ");     print NS &fortune;

    close NS;  }

 sub fortune

 { @fortunes = split(/\n%%\n/, <<'END') unless @fortunes;  A fool and his money are soon parted.

 %%

 A penny save is a penny earned.

 %%

 Ask not what your country can do for you; ask what you can do for your country.

 %%  END

 splice (@fortunes, int(rand(@fortunes)), 1)."\n";  }

2.16. MANIPULATION DE BASES DE DONNEES UTILISATEUR

2.16.1. Les donnØes et tableaux DBM

La plupart des syst?mes Unix ont une biblioth?que standard appelØe DBM. Cette biblioth?que dispose d’un outil de gestion de base de donnØes qui permet aux programmes de stocker des paires (clØ, valeur) dans une paire de fichiers du disque. Ces fichiers contiennent les valeurs de la base de donnØes entre deux appels aux programmes manipulant cette base. Les programmes peuvent crØer de nouvelles donnØes, dØtruire ou modifier des donnØes dØj existantes.

Perl permet d’accØder cet outil de DBM. Un tableau associatif est associØ une base de donnØes de DBM de la mŒme mani?re qu’on ouvre un fichier. Ce tableau associatif (tableau DBM) est ensuite utilisØ pour accØder et modifier la base de donnØes DBM.

La taille, le nombre et la nature des clØs et valeurs de la base de donnØes DBM sont limitØes; on a donc les mŒmes limitations pour le tableau DBM. En gØnØral, si on ne dØpasse pas 1000 caract?res binaires pour les clØs et les valeurs, ca passe.

2.16.2. Ouverture et fermeture des tableaux DBM

Pour associer une base de donnØes DBM     un tableau DBM, on utilise l’opØrateur dbmopen(), qui a pour syntaxe:

dbmopen(%NOM_DE_TABLEAU, "nom_du_fichier_dbm", $mode);

%NOM_DE_TABLEAU est un tableau associatif Perl. S’il contient dØj des valeurs, elles sont ØcrasØes. Ce tableau est connectØ au fichier DBM nom_du_fichier_dbm, gØnØralement stockØ sur le disque en tant que paire de fichiers: et . N’importe quel nom est acceptØ pour le tableau, mais en gØnØral on utilise des majuscules pour marquer la ressemblance avec les filehandles.

Le param?tre $mode est un nombre contr lant les droits de la paire de fichiers si ces fichiers doivent Œtre crØØs. Ce nombre est spØcifiØ en octal: la valeur 0644 donne l’acc?s tout le monde en lecture uniquement; seul le propriØtaire est autorisØ en lecture et en Øcriture. Si les fichiers existent dØj , ce param?tre n’a pas d’effet. Exemple:

dbmopen(%FRED, "mabasededonnees", 0644);

Le tableau %FRED est associØ aux fichiers et dans le rØpertoire courant. Si ces fichiers n’existaient pas, ils sont crØØs avec le mode 0644. dbmopen() retourne vrai si la base de donnØes a pu Œtre ouverte ou crØØe, faux sinon. Si on ne veut pas que les fichiers soient crØØs, il suffit de donner au mode la valeur undef; exemple:

dbmopen(%A, "/etc/xx", undef) ||  die("Impossible d'ouvrir la DBM /etc/xx. \n");

Si les fichiers et n’ont pu Œtre ouverts, ils ne sont pas crØØs et un message est renvoyØ l’utilisateur.

Le tableau DBM reste ouvert pendant toute la durØe d’exØcution du programme. Quand celuici s’ach?ve, l’association se termine aussi. On peut Øgalement mettre fin l’association avec dbmclose(); exemple:

dbmclose(%FRED);

Cet opØrateur retourne faux si quelque chose s’est mal passØ.

2.16.3. Utilisation d un tableau DBM

Une fois que la base de donnØes est ouverte, toute rØfØrence au tableau DBM est interprØtØe comme une rØfØrence la base de donnØes. Toute modification, destruction ou ajout d’une valeur du tableau engendre les entrØes correspondantes dans les fichiers de la base de donnØes. Exemple:

dbmopen(%FRED, "mabasededonnees", 0644);

%FRED{"fred"} = "bedrock"; # crée (ou modifie) un élément delete $FRED{"barney"}; # détruit un élément de la base de données

foreach $key (keys %FRED)

{ print "$key a pour valeur $FRED{$key} \n"; }

Avec l’opØrateur foreach, on parcourt deux fois le fichier de la base de donnØes: une fois pour les clØs et une seconde fois pour les valeurs. Il vaut mieux ici utiliser l’opØrateur each comme suit:

while ( ($key, $value) = each(%FRED) )

{ print "$key a pour valeur $value \n"; }

2.16.4. Bases de donnØes de longueur fixe et d’acc?s alØatoire.

Une autre forme persistante de donnØes est le fichier disque orientØ enregistrements de longueur fixe. Chaque enregistrement est composØ des mŒmes champs de longueur fixe; tous les enregistrements ont donc la mŒme longueur.

Par exemple, soit le fichier SPEINF contenant les enregistrements pour les annØes spØciales info 95; chaque enregistrement poss?de trois champs:

•  40 octets pour le nom

•  40 octets pour le prØnom

•  2 octets pour l’age

Un enregistrement a donc une longueur fixe de 82 octets.

Perl permet de manipuler de tels fichiers disques. Cependant il faut savoir:

1.    ouvrir un fichier disque en lecture et en Øcriture

2.    se dØplacer dans ce fichier

3.    rØcupØrer des donnØes en connaissant la longueur d une ligne plut t qu’en cherchant lecaract?re de fin de ligne

4.    Øcrire des donnØes sous forme de blocs de taille fixe

L’opØrateur open() prend un signe + devant ses spØcifications d’E/S pour indiquer que le fichier est ouvert en lecture et en Øcriture; exemple:

open(A, " + < b");

# le fichier b est ouvert en lecture et en écriture open(C, " + > d");

# le fichier d est créé avec les droits en lecture et en écriture

open(E, " + >> f");

# le fichier f est ouvert ou créé avec les droits en lecture et en écriture

Une fois qu’un fichier est ouvert, il faut pouvoir s’y dØplacer. On utilise pour cela l’opØrateur seek(), qui prend trois param?tres. Le premier est un filehandle; le second est un offset, interprØtØ en conjonction avec le troisi?me param?tre. En gØnØral, on donnera la valeur 0 celui-ci, de fa on ce le deuxi?me param?tre soit interprØtØ comme une nouvelle position absolue pour la prochaine lecture ou Øcriture; exemple:

seek(SPEINF, 4*82, 0);

Le pointeur est positionnØ au dØbut de la cinqui?me ligne du fichier SPEINF (la taille des enregistrements contenus dans ce fichier est 82 octets). C’est sur cette ligne que s’opØreront les prochaines entrØes et sorties.

Pour Øcrire dans le fichier de la base de donnØes, l’opØrateur print() est utilisØ, mais il faut Œtre sßr de la longueur de la donnØe Øcrite. Pour obtenir cette longueur, on fait appel l’opØrateur pack(). Exemple:

print SPEINF pack("A40A40s", $nom, $prenom, $age );

pack() permet de spØcifier que, dans un enregistrement du fichier SPEINF, les premier et deuxi?me champs ont pour longueur 40 octets et le troisi?me est un short (2 octets). $nom, $prenom et $age doivent vØrifier cela.

Pour aller chercher un enregistrement particulier dans le fichier, on utilise l’opØrateur read(). Exemple:

$nb = read(SPEINF, $buf, 82);

Le premier param?tre est un filehandle, le deuxi?me est une variable scalaire qui contiendra les donnØes qui seront lues, le troisi?me est le nombre d’octets lire. read() retourne le nombre d’octets effectivement lus.

L’opØrateur unpack() permet de dØcouper la cha ne de 82 octets qui vient d’Œtre lue; exemple:

($nom, $prenom, $age) = unpack("A40A40s", $buf);

Remarquez que les formats de pack() et unpack() sont les mŒmes. En gØnØral cette cha ne est stockØe en dØbut de programme puisqu’elle est caractØristique du fichier ØtudiØ.

2.16.5. Bases de donnØes de longueur variable

La plupart des bases de donnØes syst?me et utilisateur sont une sØrie de lignes de texte comprØhensible, avec un enregistrement par ligne. En gØnØral, elles sont modifiØes directement avec un Øditeur de texte.

Perl permet une telle mise jour des bases de donnØes constituØes de lignes gr ce l’Ødition en ligne. Cette mØthode consiste en une modification de la fa on dont l opØrateur diamant <> lit les donnØes des fichiers spØcifiØs dans la ligne de commande. En gØnØral, ce mode d Ødition est accØdØ en positionnant l option -i de la ligne de commande.

Avant de lancer l’Ødition en ligne, il faut donner une valeur la variable scalaire $^I. Cette variable est importante et nous verrons plus bas en quoi elle consiste.

Lorsque l opØrateur <> est utilisØ et que $^I a une valeur (diffØrente de undef), les lignes marquØes par ##INPLACE## dans le code suivant sont ajoutØes la liste d actions implicites de l opØrateur <>:

$ARGV = shift @ARGV; open(ARGV, "<$ARGV"); rename($ARGV, "$ARGV$^I"); ## INPLACE## unlink($ARGV); ## INPLACE## open(ARGVOUT, "> $ARGV"); ## INPLACE## select(ARGVOUT); ## INPLACE##

Les lectures effectuØes par <> sont faites partir du vieux fichier, les Øcritures sont faites sur une nouvelle copie du fichier. Le vieux fichier reste dans le fichier de backup, dont le nom est le nom du fichier suivi de l extension contenue dans la variable $^I. Ceci est rØpØtØ pour tous les fichiers de @ARGV.

En gØnØral, $^I a pour valeur .bak ou ~. Si $^I est la cha ne vide "", le vieux fichier est ØliminØ. Cependant, il faut Œtre prudent: si un incident a lieu pendant l exØcution du programme, vous perdez alors toutes vos vieilles donnØes.

Voici   une  fa on  de  changer  le  shell  de  lancement  pour  tous  les  utilisateurs  du   fichier

/etc/passwd:

             @ARGV = ("/etc/passwd");     # affectation de l’opérateur diamant

$^I = ".bak";

# écrit pour plus de sécurité while (<>)

{ # pour chaque ligne de /etc/passwd    s#:[^:]*$#:/bin/sh#;

  # change  shell de lancement en /bin/sh    print;

   # envoi la sortie sur ARGVOUT: le nouveau /etc/passwd

}

Ce programme est simple; pourtant on peut faire la mŒme chose avec une unique ligne de commande:

> perl -p -e 's#:[^:]*$#/bin/sh#' /etc/passwd

-p permet d encadrer le programme avec une boucle while incluant une instruction print.

-i permet de fixer la valeur de $^I.

-e indique que l argument qui suit est un morceau de code Perl exØcuter dans le corps de la boucle while.

Le dernier param?tre donne une valeur initiale @ARGV.

2.17. CONVERTIR D?AUTRES LANGAGES EN PERL

2.17.1. Conversion de programmes awk en Perl

Si vous avez un programme awk que vous voulez faire tourner avec Perl, vous pouvez effectuer une traduction mØcanique avec l outil a2p fourni avec Perl. Cet outil convertit la syntaxe awk en syntaxe Perl et permet, pour la majoritØ des programmes awk, d obtenir un script Perl prŒt l emploi.

Pour utiliser a2p, mettre le programme awk dans un fichier sØparØ et appeler a2p avec le nom du fichier comme argument ou avec une redirection en entrØe avec ce fichier. La sortie est un programme Perl exØcutable. Exemple:

> a2p < mon_pg_awk   > mon_pg_perl

> perl mon_pg_perl <arguments>

Un programme awk converti en Perl aura gØnØralement la mŒme fonction, mais s’exØcutera plus rapidement. Le code du programme Perl obtenu peut parfois Œtre optimisØ.

Certaines conversions ne sont pas mØcaniques. Par exemple, awk utilise l’opØrateur > pour comparer des cha nes ou des nombres, alors que Perl utilise > avec les nombres et gt avec les cha nes. a2p essaie de deviner quel opØrateur Perl convient en fonction de ce qu’il sait des opØrandes. S’il n’est pas sßr de son choix, a2p marque la ligne avec #?? (commentaire Perl) et une explication. Il vaut donc mieux consulter le script Perl obtenu apr?s conversion afin de corriger ce genre d’erreur.

Pour en savoir plus sur a2p, consulter sa page man.

2.17.2. Conversion de programmes sed en Perl

L’opØrateur s2p convertit un programme sed en programme Perl. Il s’utilise de la mŒme fa on que a2p.

Cependant il n’y a en gØnØral pas d’erreur de conversion. s2p est Øcrit en Perl!

2.17.3. Conversion de programmes shell en Perl

Il n’y a malheureusement pas de convertisseur shell/Perl. Le probl?me est que, dans un shell script, la plupart des commandes ne sont pas exØcutØes par le shell; des appels sont effectuØs des programmes indØpendants pour rØcupØrer des morceaux de cha nes, comparer des nombres, concatØner des fichiers

Donc, c’est vous de jouer au convertisseur: Øtudiez le script shell, comprenez-le et Øcrivez un script Perl rØalisant la mŒme chose! L’opØrateur system() peut vous aider traduire rapidement.

2.18. COMPLEMENTS

2.18.1. L opØrateur require

C est l Øquivalent du include du C. Des programmes Perl peuvent Œtre stockØs dans un ou plusieurs fichiers indØpendants et Œtre ensuite inclus dans tout programme Perl qui a besoin d eux; exemple:

require ' ';

permet d inclure le texte du fichier comme s il faisait partie du fichier dans lequel figure cette instruction. Du code peut ainsi Œtre partagØ entre diffØrents programmes

Perl.

Cependant, les subroutines incluses doivent retourner une valeur non nulle pour que require fonctionne. Par exemple, toutes les routines de la biblioth?que se terminent par la ligne:

1;

2.18.2. La biblioth?que Perl

Elle contient des programmes Perl utiles, Øvitant de devoir les rØØcrire soi-mŒme. Pour savoir dans quel rØpertoire elle se trouve, il suffit d imprimer le premier ØlØment du tableau @INC. La plupart des routines sont commentØes. Pour les utiliser dans un programme, il suffit d utiliser l opØrateur require ci-dessus en dØbut de programme.

2.18.3. Les Here Strings

Apr?s les cha nes entre simples ou doubles quotes, voici les here strings (mŒme chose que les here documents en shell):

$a = <<"@HEAD"."\n".$body;

To:

From: $username

Subject: What, do you think?

Date: $now HEAD

Elles ne sont vraiment pas nØcessaires.

2.18.4. Les alias

On peut faire de b un alias de a en Øcrivant *b = *a. Cela signifie que $a et $b rØfØrencent la mŒme variable, tout comme @a et @b, ou mŒme les filehandles et les formats a et b. *b peut Øgalement Œtre utilisØ localement avec l instruction local(*b).

2.18.5. L opØrateur eval() et s///e

C est l Øquivalent de l opØrateur du mŒme nom en shell. Il permet d Øvaluer du bout de code passØ en param?tre lors de l exØcution du programme Perl. Un exemple, pour Œtre plus clair:

print "Donnez la commande à exécuter : "; chop($code = <STDIN>); eval $code;

             die("eval : $@") if $@;     # on teste si eval s’est bien passé

Ce script permet d exØcuter une commande passØe par l utilisateur pendant l exØcution comme si elle faisait partie du programme.

On peut mettre du code Perl dans la cha ne de remplacement de l opØrateur de substitution si celui-ci est suivi du flag e. Cela permet d avoir des cha nes de remplacement compliquØes, faisant par exemple appel des subroutines retournant des rØsultats.

Exemple:

while(<>)

{  s/^(\S+)/$var+1/e; print;  }

Le premier mot de chaque ligne de l entrØe est remplacØ par la valeur de $var+1.

2.18.6. Le debugger

Si l on fait appel Perl avec l option -d, le script tourne sous le moniteur de deboggage. Pour conna tre les commandes de deboggage, il suffit alors de taper h: cela donne acc?s la page d aide.

En tapant simplement:

> perl -de 0 le debugger dØmarre sans script.

2.18.7. L opØrateur , (virgule)

Cet opØrateur Øvalue son opØrande gauche, Ølimine le rØsultat de cette Øvaluation, puis Øvalue son opØrande droit, retournant cette derni?re Øvaluation comme rØsultat de l expression (cela est pratique lorsque l opØrande gauche est Øvaluer uniquement pour ses effets secondaires, comme l incrØmentation d une variable ou l appel une subroutine). Exemple:

$a = ( 1, 3); affecte $a avec la valeur 3.

2.18.8. Les opØrateurs sur les bits

Il existe les opØrateurs de dØcalage de bit gauche, >>, et droite, <<. Le rØsultat dØpend cependant des propriØtØs arithmØtiques de la machine.

On dispose Øgalement des opØrateurs logiques sur les bits:

•  &, et logique

•  |, ou logique

•  ^, ou exclusif

Ces opØrateurs travaillent sur des valeurs numØriques enti?res.

2.18.9. Les paquetages

On dØsire parfois que les donnØes d un programme soient privØes et inaccessibles d autres programmes. Perl dispose pour cela d un mØcanisme de paquetage, qui fournit un espace d adressage indØpendant. On peut alors avoir deux variables portant le mŒme nom dans deux programmes diffØrents: elles sont indØpendantes. Le mot rØservØ package permet de dØclarØ des paquetages, n importe oø dans le programme. Une telle dØclaration est effective de la ligne oø elle est effectuØe la fin du bloc la contenant. Exemple:

package pecan; sub tarte

{ $reponse = <STDIN>; # une variable   package canari;

  $reponse = <STDIN>;  # une autre variable }

Il est possible de rØfØrencer les variables et les filehandles d un paquetage l intØrieur d autres paquetages; il suffit de faire prØcØder leur nom du nom du paquetage et d une quote simple. L exemple prØcØdent devient alors:

sub pecan'tarte

{ $pecan'reponse = <STDIN>;

$canari'reponse = <STDIN>;     }

Si le nom du paquetage est nul, ce paquetage est considØrØ comme le paquetage principal ou main package. Alors $'tarte est la mŒme chose que $main'tarte.

Seuls les identificateurs dont les noms commencent par une lettre sont stockØs dans la table de symboles du paquetage. Les autres symboles (toutes les variables spØciales) et STDIN, STDOUT, STDERR, ARGV, AGVOUT, ENV, INC et SIG sont conservØs dans le paquetage principal.

La table de symboles de chaque paquetage est stockØe dans un tableau associatif situØ dans la table de symboles du paquetage principal. Le nom de la table de symboles du paquetage bleu n est autre que %_bleu.


 

3. EXEMPLE D?APPLICATION


 

3.1. UN SYSTEME DE RESERVATION DE VOLS

Comme nous l avons vu dans le chapitre 2, Perl a des domaines d utilisation tr?s variØs:

•  Manipulation de bases de donnØes

•  Administration du syst?me

•  Manipulation de fichiers, de textes, de processus • Communication interprocessus

En voici un exemple concret: un syst?me de rØservation de vols.

Le fichier place_disp joue le r le de base de donnØes. Il contient des enregistrements de la forme:

code-vol:ville-départ:ville-arrivée:heure-départ:heurearrivée:date-départ:classe:nb-places-dispo:prix

Le fichier suivant est utilisØ pour tester le programme:

AI132:Paris:Nice:10h00:11h20:22/06/95:eco:8:400

AF330:Lille:Toulouse:22h30:23h50:23/07/95:club:16:1030

BA120:Paris:Londres:15h40:17h00:21/08/95:prem:8:2500

AF562:Nice:Paris:21h00:22h20:21/07/95:eco:44:400

AF457:Nice:Paris:22h00:23h20:21/07/95:eco:20:400

IB120:Lisbonne:Lille:12h00:14h30:10/08/95:club:23:3000

KL498:Amsterdam:Nice:17h00:19h30:17/09/95:eco:60:1500

Une interface permet l’utilisateur d’indiquer le vol qui l’intØresse. Le fichier place_disp est parcouru, la recherche d’un vol qui correspond aux saisies de l’utilisateur.

Il est possible d’effectuer des rØservations. Le fichier reservation re oit alors les donnØes.

Enfin, des factures peuvent Œtre imprimØes; pour cela, le fichier reservation est consultØ.


 

3.2. LE PROGRAMME PERL

################# Formats #######################################

format ENTETE =

Vol @<<<<<<<<< -> @<<<<<<<<< le @<<<<<<<

$VD, $VA, $date .

format FORMAT1 =

=============================================================== heure depart| heure arrivee| code vol| classe| nb places| prix ===============================================================

@|||| | @||||        | @||||   | @|||| | @||      | @<<<<

$HD, $HA, $codevol, $classe, $nb_place, $prix

.

format MENU =

**************************************************************

** Bienvenue sur notre systeme de reservation!       **

************************************************************** Nous vous offrons les services suivants :

1.    renseignements/reservations

2.    factureq. quitter

. format FORMAT3 =

Ville de depart: @<<<<<<<<< $VA

Ville d'arrivee: @<<<<<<<<< $VD .

format FACTURE =

============================================================= FACTURE

=============================================================

no reservation : @<<<<

$no_resa

nom : @<<<<<<<<<

$nom

@<<<<<<< @<<<<<<<<<   @<<<< $date, $VD, $HD

@<<<<<<<<<   @<<<<

$VA, $HA

code du vol : @<<<<

$codevol classe : @<<<<

$classe

somme a payer : @<<<<

$prix somme versee  : @<<<<

$verse

-----

somme due     : @<<<<

$prix-$verse .

format ENREGISTRE =

@<<<<:@<<<<<<<<<:@<<<<:@<<<<<<<<<:@<<<<:@<<<<<<<<<:@<<<<:@<<<<<<<:@< <<<:@<<<<:@<<<<

$no_resa, $nom, $codevol, $VD, $HD, $VA, $HA, $date, $classe, $prix, $verse .

################## Programme principal #########################

# initialisation des numeros de resa

$no_resa = 0;

#lancement

&menu_principal($no_resa);

################## Subroutines ################################

sub menu_principal

{

  #### nettoyage de l'ecran   system("clear");

  #### recuperation du numero de reservation

  $no_resa = $_[0];

  #### impression du menu

  $~ = "MENU";   write;   print "Votre choix: "; chop($choix=<STDIN>);   print "\n";

  #### Traitement du choix de l'utilisateur   if ($choix == 1)

  {

    #### nettoyage de l'ecran     system("clear");

    #### obtenir des renseignements et eventuellement reserver

    #### Saisie des donnees et

    #### appel a la subroutine renseign     &renseign(&saisie_cherch, $no_resa);

  }

  elsif ($choix == 2)

  {

    #### nettoyage de l'ecran     system("clear");

    #### imprimer une facture

&facture;   }

  else

  {

    #### On sort du programme     exit 0;   } }

sub saisie_cherch

{

    #### Saisie des villes de depart, d'arrivee et de la date de depart

    print "Ville de depart: ";     chop($VD = <STDIN>);     print "\n";

    print "Ville d'arrivee: ";     chop($VA = <STDIN>);     print "\n";     print "Date de depart: ";     chop($date = <STDIN>);     print "\n";

    #### valeur de retour

@donnees = ($VD, $VA, $date);

}

sub reserv

{

  #### Saisie des donnees

  print "Nom du client: ";   chop($nom = <STDIN>);   print "\n";

  ($VD, $VA, $date, $o_resa, $codevol, $HD, $HA, $classe, $nb_place,

$prix) = @_;

  print "Accompte: ";   chop($verse = <STDIN>);   print "\n";

  #### mise a jour du numero de reservation

  $no_resa ++;

  # modification du nombre de places disponibles   # ouverture en lecture du fichier place_disp   open(A, "< place_disp");

  # ouverture en ecriture d'un fichier temporaire   open(C, ">> temp_fic");

  # parcours du fichier place_disp   while(<A>)

  {

    $sauv = $_;

    if ( $sauv =~ /^$codevol:$VD:$VA:$HD:$HA:$date:$classe:/i)

    {

      $sauv = $&;

($nb_place, $prix) = split(/:/, $');

$nb_place --;

$rempl = $sauv.$nb_place.":".$prix;       s/^.*$/$rempl/;

    } print C;   }   close(A);   close(C);   unlink("place_disp"); open(A, ">> place_disp");   open(C, "< temp_fic");   while(<C>)

  { print A unless (/^$/); }   close(A);   close(C);   unlink("temp_fic");

  #### enregistrement dans le fichier reservation   open(B, ">> reservation");   select(B);   $~ = "ENREGISTRE";   write; select(STDOUT);

  print "\n\nReservation effectuee.\n\n\n";   print "numero de resa = $no_resa\n\n\n";

  print "    Tapez q pour quitter\n          r pour menu principal\n"; chop($choix = <STDIN>);

  #### traitement du choix de l'utilisateur   if ($choix eq 'r')

  {

    #### nettoyage de l'ecran     system("clear");

    #### retour au menu pricipal

&menu_principal($no_resa);

   }

  else

  {

    #### on sort du programme     exit 0;

  } }

sub renseign

{

  #### Initialisations

  $trouve = 0;

  @tab1 = ($VD, $VA, $date, $no_resa) = @_;

  #### ouverture en lecture du fichier place_disp   open (A, "< place_disp");

  #### Consultation du fichier PLACE_DISP   #### Recherche des renseignements

  BLOC: while (<A>)

  {

    #### Sauvegarde de $_

    $sauv = $_;

    #### Recherche des vols remplissant les conditions     if (/$VD:$VA:.*:.*:$date/i)

    {

      $_ = $sauv;

      $~ = "ENTETE";       write;

      #### Recuperation des informations

      @tab2 = ($codevol, $HD, $HA, $classe, $nb_place, $prix) =

/^(\S+):.*:.*:(\S+):(\S+):.*:(\S+):(\S+):(\S+)$/;

      #### un vol a ete trouve

$trouve ++;

      #### Affichage des informations

      $~ = "FORMAT1";       write;       print "    Tapez q pour quitter \n          r pour reserver\n s pour suivant\n          a pour A/R\n";       chop($choix = <STDIN>);

      #### traitement du choix de l'utilisateur       if ($choix eq 'q')

      {

#### on sort du programme         exit 0;       }

      elsif ($choix eq 'r')

      {

#### nettoyage de l'ecran         system("clear");

#### fermeture de place_disp close(A);

#### on effectue une reservation

&reserv(@tab1, @tab2);

      }

      elsif ($choix eq 'a')

      {

#### nettoyage de l'ecran         system("clear");

#### on recherche un retour

        $~ = "FORMAT3"; write; print "Date de retour: "; chop($date = <STDIN>); print "\n";

#### Inversion des villes de depart et d'arrivee

$sauv = $VA; $VA = $VD;

$VD = $sauv;

#### Reinitialisation de l'index

$trouve = 0;

#### Modification de @tab1

     @tab1 = ($VD, $VA, $date, $no_resa);

#### Reinitialisation du pointeur sur la ligne courante de place_disp

open(A,"< place_disp");

#### on relance la recherche next BLOC;

      }

    }   }

  if ($trouve == 0)

      {

#### aucun vol n'a ete trouve correspondant aux exigences print "Pas d'avion pour ce trajet a cette date.\nVoulez-vous

saisir une autre date (o/n)? "; chop($rep = <STDIN>); print "\n"; close(A);

#### traitement du choix de l'utilisateur if ($rep=~/^o/)

{

  #### nettoyage de l'ecran           system("clear");

  #### saisie d'une nouvelle date       print "Date de depart: ";   chop($date = <STDIN>);         print "\n";

  #### on relance la recherche

&renseign($VD, $VA, $date, $no_resa);

 }

 else

 {

#### nettoyage de l'ecran            system("clear");

   #### retour au menu principal

&menu_principal($no_resa);

 }       }

else       {

#### Il n'y a plus d'autres vols correspondant aux exigences print "\n\n\n\n"; print "Pas d'autre vol.";

close(A);

print "\n\n\n    Tapez q pour quitter\n          a pour autre

recherche\n          r pour menu principal\n"; chop($choix = <STDIN>);

#### traitement du choix de l'utilisateur if ($choix eq 'q')

{

  #### on quitte le programme   exit 0;

        }

elsif ($choix eq 'a')

{

  #### nettoyage de l'ecran           system("clear");

  #### une autre recherche est lancee   &renseign(&saisie_cherch, $no_resa);

}

else

{

  #### nettoyage de l'ecran           system("clear");

  #### retour au menu principal

&menu_principal($no_resa);

}

      } }

sub facture

{

   #### initialisation de l'index

   $trouve = 0;

   #### saisie du numero de resa    print "Donnez le numero de reservation: ";    chop($no_resa = <STDIN>);    print "\n";

   #### recherche dans le fichier des reservations    open(B, "< reservation");    while (<B>)    { $sauv = $_;      if (/^$no_resa/)

     {

($no_resa, $nom, $codevol, $VD, $HD, $VA, $HA, $date,

$classe, $prix, $verse) = split(/:/, $sauv);

$trouve ++;

       #### affichage        $~ = "FACTURE";        write;

     }

   }

   if ($trouve == 0)

   {

     #### aucune reservation n'a ete trouvee      print "Aucune reservation ne correspond a ce numero.\n";    }

   #### autre facture?    print "    Tapez a pour autre facture\n          r pour menu principal\n          q pour quitter\n";    chop($choix = <STDIN>);

   #### traitement du choix de l'utilisateur    if ($choix eq 'a')

   {

     #### nettoyage de l'ecran      system("clear");

     #### impression d'une autre facture

&facture;    }

   elsif ($choix eq 'r')

   {

     #### nettoyage de l'ecran      system("clear");

     #### retour au menu principal

&menu_principal;

   }

   else

   {

     #### on quitte le programme      exit 0;

   }

}


 

3.3. RESULTATS

************************************************************** **     Bienvenue sur notre systeme de reservation!       ** ************************************************************** Nous vous offrons les services suivants :

1.    renseignements/reservations

2.    facture q.  quitter

Votre choix: 1

Ville de depart: paris

Ville d'arrivee: londres

Date de depart: 21/08/95

Vol paris      -> londres    le 21/08/95

=============================================================== heure depart| heure arrivee| code vol| classe| nb places| prix ===============================================================

15h40 | 17h00        | BA120   |  prem |  8       | 2500

    Tapez q pour quitter           r pour reserver           s pour suivant           a pour A/R s

Pas d'autre vol.

    Tapez q pour quitter           a pour autre recherche           r pour menu principal a

Ville de depart: paris

Ville d'arrivee: nice

Date de depart: 22/06/95

Vol paris      -> nice       le 22/06/95

=============================================================== heure depart| heure arrivee| code vol| classe| nb places| prix =============================================================== 10h00       | 11h20        | AI132   |  eco  |  8       | 400

    Tapez q pour quitter           r pour reserver           s pour suivant           a pour A/R a

Ville de depart: nice

Ville d'arrivee: paris

Date de retour: 21/07/95

Vol nice       -> paris      le 21/07/95

=============================================================== heure depart| heure arrivee| code vol| classe| nb places| prix =============================================================== 21h00       | 22h20        | AF562   |  eco  |  45      | 400

    Tapez q pour quitter           r pour reserver           s pour suivant           a pour A/R s

Vol nice       -> paris      le 21/07/95

=============================================================== heure depart| heure arrivee| code vol| classe| nb places| prix =============================================================== 22h00       | 23h20        | AF457   |  eco  |  21      | 400

    Tapez q pour quitter           r pour reserver           s pour suivant           a pour A/R r

Nom du client: poiraud Accompte: 100 numero de resa = 1

Reservation effectuee.

    Tapez q pour quitter           r pour menu principal r

**************************************************************

** Bienvenue sur notre systeme de reservation!          **

************************************************************** Nous vous offrons les services suivants :

1.    renseignements/reservations

2.    facture q.  quitter Votre choix: 2 Donnez le numero de reservation: 1

============================================================= FACTURE

============================================================= no reservation : 1         nom : poiraud

21/07/95 nice         22h00            paris        23h20

code du vol : AF457         classe : eco

somme a payer : 400                                 somme versee  : 100 ----                                somme due     : 300

    Tapez a pour autre facture           r pour menu principal           q pour quitter r

**************************************************************

** Bienvenue sur notre systeme de reservation!          **

************************************************************** Nous vous offrons les services suivants :

1.    renseignements/reservations

2.    facture q.  quitter Votre choix: 1

Ville de depart: lille

Ville d'arrivee: toulouse

Date de depart: 22/07/95

Pas d'avion pour ce trajet a cette date.

Voulez-vous saisir une autre date (o/n)? o

Date de depart: 23/07/95

Vol lille      -> toulouse   le 23/07/95

=============================================================== heure depart| heure arrivee| code vol| classe| nb places| prix ===============================================================

22h30 | 23h50        | AF330   |  club |  17      | 1030

    Tapez q pour quitter           r pour reserver           s pour suivant           a pour A/R r

Nom du client: grossiord Accompte: 0

numero de resa = 2

Reservation effectuee.

    Tapez q pour quitter           r pour menu principal q

Apr?s ces tests, l’Øtat du fichier reservation, initialement vide, est:

1     :poiraud     :AF457:nice     :22h00:paris    :23h20:21/07/95:eco :400 :100

2     :grossiord :AF330:lille       :22h30:toulouse :23h50:23/07/95:club :1030 :0


 

4.   EXERCICES


 

4.1.   ENONCES

4.1.1. Chapitre 2.1.

Ecrire un programme qui attend que l utilisateur saisisse un rayon avant de calculer le pØrim?tre du cercle.

4.1.2. Chapitre 2.2.

Ecrire un programme qui lit un chiffre et une liste de cha nes (chacune sur une ligne) et qui retourne la ligne sØlectionnØe par le chiffre.

4.1.3. Chapitre 2.3.

1.    Ecrire un programme demandant la tempØrature extØrieure, et affichant « trop chaud! » sielle est supØrieure 30 , « trop froid! » si elle est infØrieure 20 , « impeccable! » si elle est comprise entre 20 et 30 .

2.    Ecrire un programme qui lit une liste de cha nes (chacune sur une ligne) et les affiche dansl ordre inverse (sans utiliser reverse, bien sßr!).

4.1.4. Chapitre 2.4.

Ecrire un programme qui lit une sØrie de mots (un mot par ligne) et qui affiche le nombre de fois que figure chaque mot dans la liste.

4.1.5. Chapitre 2.5.

Ecrire un programme faisant la mŒme chose que cat mais inversant l ordre des lignes.

4.1.6. Chapitre 2.6.

Ecrire un programme qui parcourt /etc/passwd, cherche deux utilisateurs ayant le mŒme nom et affiche ces noms.

4.1.7. Chapitre 2.7.

Ecrire une subroutine qui prend les valeurs numØriques de deux chiffres, les additionne et affiche le rØsultat sous la forme: "deux plus deux égale quatre. "

4.1.8. Chapitre 2.8.

Modifier le probl?me prØcØdent de fa on ce que l opØration soit rØpØtØe jusqu ce que le mot end soit saisi.

4.1.9. Chapitre 2.9.

Ecrire un programme prenant un nom de fichier d entrØe, un nom de fichier de sortie, un pattern chercher, une cha ne de remplacement, et qui remplace toute occurrence du pattern dans le fichier d entrØe par la cha ne de remplacement et met le rØsultat dans le fichier de sortie.

4.1.10. Chapitre 2.10.

Ecrire un programme ouvrant /etc/passwd et affichant les logins utilisateur, les UID et les vrais noms sous forme de colonnes.

4.1.11. Chapitre 2.11.

Ecrire un programme qui permet de changer de rØpertoire et de se retrouver dans celui saisi par l utilisateur, et qui affiche la liste des fichiers de ce rØpertoire dans l ordre alphabØtique.

4.1.12. Chapitre 2.12.

Ecrire un programme rØalisant la mŒme chose que mv.

4.1.13. Chapitre 2.13.

Ecrire un programme qui rØcup?re tous les vrais noms d utilisateur de /etc/passwd et transforme la sortie de la commande who, en rempla ant les logins par les vrais noms.

4.1.14. Chapitre 2.14.

Ecrire un programme affichant les logins et les vrais noms d utilisateur du fichier /etc/passwd, ordonnØs par le prØnom.

4.1.15. Chapitre 2.15.

Ecrire un programme crØant une correspondance entre UID et vrai nom d utilisateur       partir de /etc/passwd et utiliser cette correspondance pour afficher une liste de vrais noms appartenant chaque groupe du fichier /etc/group.

4.1.16. Chapitre 2.16.

Ecrire deux programmes: l un qui lit les donnØes de l opØrateur diamant, les dØcoupe en mots, et met jour un fichier DBM indiquant le nombre de fois qu appara t chaque mot; l autre qui ouvre un fichier DBM et affiche les rØsultats dans l ordre dØcroissant.

4.1.17. Chapitre 2.17.

Convertir le script shell suivant en Perl:

cat /etc/passwd | awk -F: '{print $1, $6}' | while read user home do

newsrc="$home/.newsrc" if [ -r $newsrc ] then if grep -s  '^comp\.lang\.perl: ' $newsrc then  echo "$user is a good person, and read ! " fi

fi done

4.2.   SOLUTIONS

Ces solutions ne sont pas uniques!

4.2.1.

$pi = 3.14; print "Donnez le rayon du cercle : \n"; chop($rayon = <STDIN>);

print "Le périmètre du cercle est : ".(2*$pi*$rayon);

4.2.2.

print "Donnez un chiffre: \n"; chop($compte = <STDIN>); print "Donnez une liste de chaînes, terminez l’entrée par ^D:

\n";

@tab = <STDIN>;

print "La $compteième chaîne est $tab[$compte-1].\n";

4.2.3.

1.   print "Donnez la température ambiante : \n";chop($temp = <STDIN>); if ($temp > 30)

{ print "Trop chaud!\n"; } elsif ($temp < 20) { print "Trop froid! \n"; } else

{ print "Impeccable!\n");

2.   print "Donnez la liste de chaînes, terminez l’entrée avec ^D:

\n";

@liste = <STDIN>; $i = $#liste-1; unless ($i == -1)

{ print "$liste[$i--]\n"; } # on peut aussi utiliser pop()

4.2.4.

print "Donnez une liste de mots : \n";

@liste = <STDIN>;

$tab{chop(shift(@liste))} ++; while ( ($cle, $val) = each(%tab) )

{ print "Le mot $cle apparaît $val fois.\n";  }

4.2.5.

print reverse <>;

4.2.6.

while (<>)

{ ($user, $pass, $uid, $gid, $gcos) = split(/:/);

   ($real) = split(/,/,$gcos);

   ($first) = split(/\s+/, $real);

$seen{$first}++;

} foreach (keys %seen)

{  if ($seen{$_} > 1)

    { print "$_ a été vu $seen{$_} fois.\n"; }

}

4.2.7.

sub card

{ @card_map = (0, "un", "deux", "trois", "quatre", "cinq",

"six", "sept", "huit", "neuf");    local($nombre) = @_;    if ($card_map[$nombre])    {  $card_map[$nombre]; }    else    { $nombre; }

print "Donnez le premier nombre: \n"; chop($prem = <STDIN>); print "Donnez le deuxième nombre: \n"; chop($deux = <STDIN>);

$message = &card($prem) . "plus" . &card($deux). "égale" .

&card($prem+$deux) . ".\n"; $message =~ s/^./\u$&/; print $message;

4.2.8.

sub card { } # même que pour l’exercice précédent

while () { ##NEW##    print "Donnez le premier nombre: \n";    chop($prem = <STDIN>);    last if $prem eq "end"; ##NEW##    print "Donnez le deuxième nombre: \n";    chop($deux = <STDIN>); last if $deux eq "end"; ##NEW##

$message=&card($prem) ."plus" .&card($deux). "égale"

.&card($prem+$deux) . ".\n";   $message =~ s/^./\u$&/;    print $message;

} ##NEW##

4.2.9.

print "Nom du fichier d’entrée: \n"; chop($fic_in = <STDIN>); print "Nom du fichier de sortie: \n"; chop($fic_out = <STDIN>); print "Pattern à rechercher: \n"; chop($pattern = <STDIN>); print "Chaîne de remplacement: \n"; chop($chaine = <STDIN>); open (IN, $fic_in) || die("Impossible d’ouvrir $fic_in!\n"); die("Je n’écraserai pas $fic_out!\n) if -e $fic_out; open (OUT, "> $fic_out") || die("Impossible de créer

$fic_out!\n"); while (<IN>)

{ s/$pattern/$chaine/g;    print OUT $_;  } close(IN); close(OUT);

4.2.10.

open (PW, "/etc/passwd") || die("Comment vous êtes-vous loggé?

\n"); while (<PW>)

{ ($user, $passwd, $uid, $gid, $gcos) = split(/:/);

   ($real) = split(/,/, $gcos);    write;  }

format STDOUT =

@<<<<<<< @>>>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

            $user,           $uid,           $real

.

4.2.11.

print "Où voulez-vous aller? :\n"; chop($rep=<STDIN>); chdir ($rep) || die ("Impossible d’accéder ce répertoire!\n"); foreach (<*>) { print "$_\n"; }

4.2.12.

($old, $new) = @ARGV; if (-d $new)

{  ($base = $old) =~ s#.*/##;     $new .= "/$base";  } rename ($old, $new);

4.2.13.

open (PW, "etc/passwd"); while (<PW>)

{ chop;

   ($user, $passwd, $uid, $gid, $gcos) = split(/:/);

   ($real) = split(/,/, $gcos);    $real{$user} = $real;  } close(PW);

open (WHO, "who |") || die ("Impossible d’ouvrir le pipe du who!\n"); while (<PW>)

{ ($login, $reste) = /^(\S+)\s+(.*)/;    $login = $real{$login} if $real{$login}; printf "%-30s %s\n", $login, $reste;  }

4.2.14.

open (PW, "etc/passwd"); while (<PW>)

{ chop;

   ($user, $passwd, $uid, $gid, $gcos) = split(/:/);

   ($real) = split(/,/, $gcos);

$real{$user} = $real;

   ($prenom =  $real) =~ s/^(.*[^a-z])?([a-z]+.*).*/$2/i;

   $prenom =~ tr/A-Z/a-z/;    $prenom{$user} = $prenom; } close(PW); for (sort by_last keys %prenom) { print "%30s  %8s\n", $real{$_}, $_;  }

sub by_last

{ ($prenom{$a} cmp $prenom{$b}) || ($a cmp $b); }

4.2.15.

$: = " ";

while (@pw = getpwent)

{ ($user, $gid, $gcos) = @pw[0, 3, 6];

   ($real) = split(/,/, $gcos);

$real{$user} = $real;

$members{$gid} .= " $user";

   ($prenom = $user) =~ s/^(.*[^a-z])?([a-z]+.*).*/$2/i;

   $prenom =~ tr/A-Z/a-z/;    $prenom{$user} = $prenom; }

while (@gr = getprent)

{ ($gname, $gid, $members) = @gr[0, 2, 3];

$members{$gid} .= " $members";    $gname{$gid} = $gname;  }

for $gid (sort by_gname keys %gname)

{ %all = ( );    for (split(/\s+/, $members{$gid}) )

   { $all{$_}++ if length $_;  }

   @members = ( );    foreach (sort by_last keys %all)    { push(@members, "$real{$_} ($_)"); }    $memberlist = join(", ", @members);    write; }

sub by_gname

{ $gname{$a} cmp $gname{$b}; }

sub by_last

{ ($last{$a} cmp $last{$b}) || ($a cmp $b) ; }

format STDOUT =

@<<<<<<<< @<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$gname{$gid}, "($gid) ", $memberlist

~~

^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $memberlist .

4.2.16.

# programme 1 dbmopen (%MOTS, "mots", 0644); while (<>)

{ foreach $mot ( split(/\W+/) )

    { $MOTS{$mot}++;  }

} dbmclose(%MOTS);

# programme 2 dbmopen (%MOTS, "mots", undef); foreach $mot ( sort { $MOTS{$b} <=> $MOTS{$a} } keys %MOTS )

{  print "$mot $MOTS{$mot}\n" ;  } dbmclose(%MOTS);

4.2.17.

for ( ; ; )

{ ($user, $home) = (getpwent)[0,7];    last unless $user;    next unless open(N, "$home/.newsrc");    next unless -M N < 30;    while (<>)

   {  if (/^comp\.lang\.perl:/)

{ print "$user is a good person and reads !\n";    last;

}

   }

}


 

ANNEXE : LE GUIDE DE REFERENCE DE PERL

 


46