

COURS
Le Langage Perl
Introduction aux interfaces cgi-bin
Edition : 97-98
Auteur : V. FREMAUX / Département Informatique
Résumé : Définit les grandes lignes des interfaces cgi-bin pour applications clients-serveurs Internet. Résume les élements essentiels du langage Perl, l'un des langages utilisés pour ces interfaces.
Présupposés : C, UNIX (utilisateur)
Les interfaces cgi-bin
Contexte
L’évolution des techniques réseau, leur généralisation dans un contexte ouvert (Internet) ou multisite (Intranet) ont conduit à une généralisation et une standardisation des processus engagés dans la notion de client-serveur.
L’ancienne notion de client-serveur, utilisée largement à l’intérieur de l’entreprise, sur des concepts de {mainframe, terminaux}, puis à travers l’évolution de la télématique via réseaux Télécom de données, s’est considérablement développé et à du s’adapter à la généralisation du concept réseau.
Les interfaces cgi-bin sont aujourd’hui la réponse la plus commune à un besoin d’interactivité de la présentation d’information, et est abondamment implémentée sur les serveurs Internet.
Définition
Une interface cgi-bin est constitué d’un exécutable qui peut être écrit dans n’importe quel langage de programmation, capable de recevoir sur le flux d’entrée standard, ou en arguments, les données correspondant à une "requête" émise par le "client" via un "formulaire", d’analyser et traiter ces données, et capable de lui donner une réponse ou d’exécuter une action telle qu’inscription dans une base de données, émission d’un courrier électronique, d’un fax, mise en page dynamique d’un résultat de recherche, etc.
Langages courants
A priori, n’importe quel langage de programmation pourrait convenir, du moment que les ressources du langage permettent :
- La lecture du flux de donnée d’entrée ou la récupération de paramètres donnés par la ligne de commande.
- L’écriture d’une réponse sur le flux standard de sortie, par défaut redirigé vers le socket d’arrivée de l’utilisateur.
Historiquement, le développement de serveurs Internet ayant été très fortement lié au monde Unix, les deux langages majeurs actuels servant au codage des cgi-bin sont le C et le PERL. L’évolution rapide des technologies réseau fait apparaître petit à petit des cgi-bin codés en Java. Leur nombre est croissant, mais encore largement minoritaire par rapport aux " serveurs " écrits en C ou en Perl.
Ce cours présente principalement les techniques d’écriture d’interfaces CGI en langage Perl, qui présente l’avantage d’être un langage interprété (pas de compilation préalable), et dispose de structures de données très puissantes pour la gestion de données sous forme de chaînes de caractères. De plus, tout comme le shell Unix et , le Perl dégage l’utilisateur des soucis d’allocation dynamique de mémoire, et offre une grande souplesse d’écriture de part son "typage" faible (les variables utilisent des types implicites qui sont analysés à l’interprétation par Perl, et qui ne demandent pas de précautions particulière dans la majorité des cas).
La contrepartie de cette souplesse est une certaine limitation du champ d’action du langage. Le C dispose en effet d’une bibliothèque bien plus large de fonctions et structures prédéfinies. En outre la syntaxe du Perl, récupérant de nombreuses sémantiques du shell Unix et du langage awk, rend ce langage plus ardu à maîtriser.
Le rôle du CGI dans une architecture réseau

Le rôle essentiel du cgi-bin dans une architecture Web est de récupérer les données fournies via un formulaire, et de répondre au client. Le cgi est l’interface unique qui rassemblera tous les éléments de réponse à réunir pour constituer la réponse attendue par le client, ou qui déclenchera toutes les actions demandées par le client.
Le circuit d'un traitement client-serveur par CGI
Le traitement client-serveur dans une architecture Web passe par plusieurs intermédiaires protocolaires.
Les données du formulaire telles qu'entrées par l'utilisateur sont tout d'abord encapsulées dans une requête HTTP émise par le navigateur, elle-même encapsulée dans un couple de protocoles TCP/IP pour transmission vers le serveur.
Arrivée au serveur, la requête est traitée par le serveur HTTP, dont la charge est de déclencher l'exécution du programme "serveur". Cette exécution peut être directe, dans le cas d'un fichier exécutable (C, C++, Pascal, Java), ou déléguée à un interpréteur (DOS, Perl, shell unix). Le serveur devra de ce fait être configuré pour appeler cet interpréteur, et lui demander l'exécution du script attendu. Le serveur devra de plus être renseigné sur les chemin d'accès valides aux scripts.
Le serveur, après traitement, récupère la sortie standard du script, et intègre celle-ci sous forme d'une entité HTTP valide, qui sera renvoyée au demandeur.
Réception des données de formulaire
L’implémentation du tag <FORM> du HTML présente deux méthodes pour transmettre les données du client :
- la méthode POST : Les données sont émises après encodage URL et sont dirigées sur le flux <STDIN> du cgi.
Dans ce cas, la taille transmissible n’est pas limitée. On connaît par ailleurs la taille de ce que contient le flux <STDIN> par la lecture de la variable d'environnement $ENV{'CONTENT_LENGTH'}
- la méthode GET : Les données sont encodées URL, puis présentées comme argument de la commande représentée par le cgi-bin. Les données seront accessibles via la variable système $ENV{'QUERY_STRING'}.
Inconvénient : le nombre de caractères total (chemin et nom du cgi-bin + chaîne d’argument) transmis est limité à 256 caractères sur certains systèmes (et 1024 sur d'autres) (taille maximale d’une ligne de commande).
Les arguments du formulaire sont transmis selon la convention CGI, c'est à dire sous la forme d'une chaîne de multiples noms=valeurs séparés par un caractère &. Tous les caractères des noms ou des valeurs non alphanumériques sont remplacés par leur encodage %[hexdigit][hexdigit] donnant le code ASCII du caractère, excepté l'espace qui est conventionnellement remplacé par un '+'.
Exemple type de chaîne de paramètres CGI:
Nom1=valeur1&Nom2=valeur+a+espaces&Nom3=valeur+%23+avec+%23+caracteres+%23+speciaux
Règles importantes pour les paramètres provenant du décodage de formulaires HTML
Renvoi de réponse au client
Par défaut, le flux <STDOUT> du cgi-bin est connecté au socket de retour de l’appelant, cette socket se traite au niveau HTTP. Il sera donc impératif de préciser le champ "Content-Type: text/html" avant toute écriture d’une réponse sous forme d’une "page" Web dynamique.
L’écriture de réponse se fait par toute fonction d’écriture habituellement routée vers <STDOUT> (print, putc, etc).
Le langage Perl
Présentation
Origines du langage
Le Perl ou Practical Extraction and Report Language est une extension du script shell, langage de programmation système sous Unix et a été développé par Larry Wall aux Etats-Unis. Le Perl intègre un grand nombre d'éléments syntaxiques du C, pour le traitement "basique" de "variables" telles que l'on peut les trouver dans d'autres langages structurés tels que le Pascal, le Fortran. De plus, comme tout script shell, il récupère la capacité de compacité syntaxique des shells Unix, et la capacité à gérer des objets de type chaînes de caractère
Caractéristiques
Typage faible non déclaratif
Le Perl, à l’instar du langage script shell, est très libéral en matière de types de variables. Les variables sont automatiquement affectées à un type au moment de leur première utilisation. En outre, le langage Perl n’impose pas, contrairement au C, une déclaration préalable des variables.
Exemple :
#!/bin/perl
$variable1 = 12 ;
$variable2 = "une chaîne" ;
$variable3 = 1.2e-4 ;
Dans l'exemple précédent, la variable variable2 est automatiquement initialisée du type "chaîne", la variable variable1 du type entier, et la variable variable3 du type flottant.
Autoallocation de mémoire
Le Perl prend en charge dynamiquement l’allocation mémoire nécessaire aux structures de données, qu’elles soient scalaires ou tableaux.
Exemple :
#!/bin/perl
$tableau[2] = "12" ;
Le début de fichier précédent crée un tableau de 3 éléments et alloue automatiquement l'espace nécessaire pour deux éléments vides, et un non vide contenant la chaîne "12".
Si dans la suite du programme, la ligne :
$tableau[10] = 23.4e+12 ;
apparaît, le tableau est implicitement étendu en mémoire sans autre intervention du programmeur.
Equivalence scalaire/chaîne
Le Perl résout automatiquement la conversion de variables exprimées en chaîne de caractères en variables de type scalaire, dans la mesure où la chaîne peut être interprétée comme tel. Si la chaîne ne peut être interprétée comme un nombre valide, toute utilisation de la chaîne dans une expression numérique conduira à l'interprétation d'une valeur numérique nulle.
Exemple 1 :
#!/bin/perl
$variable_num = 245 ;
$variable_txt = "250" ;
$somme = $variable_num + $variable_txt ;
print("$somme") ;
Exemple 2 :
#!/bin/perl
$variable_num = 245 ;
$variable_txt = "une chaîne texte" ;
$somme = $variable_num + $variable_txt ;
print("$somme") ;
Dans l'exemple 1 les deux variables variable_num et variable_txt sont tantôt un nombre, tantôt une chaîne. Et pourtant le résultat inscrit dans la somme est bien 500. La fonction print convertit implicitement la valeur numérique 500 en chaîne "500" pour en effectuer l'affichage.
Dans l'exemple 2, le résultat de la somme est 245, la chaîne "une chaîne texte" valant 0 dans son interprétation numérique.
Autodimensionnement des expressions
Le Perl dispose d'une caractéristique extrêmement utile, et qui lui donne une grande partie de sa puissance. C'est celle qui consiste à automatiquement dimensionner l'action de certaines expressions suivant que la variable réceptacle est une variable scalaire, ou une liste.
De nombreuses fonctions standard du Perl ont ainsi un double fonctionnement, et permettent des opérations globales sur des tableaux avec la même syntaxe qu'une opération sur une variable scalaire :
#!/bin/perl
$variable_scalaire = <STDIN> ;
@variable_tableau = <STDIN> ;
Les deux lignes ci-dessus ont bien la même sémantique (celle de lire dans STDIN). Leur action est cependant différente :
- La première écriture vient lire une ligne du tampon STDIN en s'arrêtant au premier \n qu'elle rencontre.
- La deuxième lit tout le tampon STDIN, et range chaque ligne dans une nouvelle "case" du tableau @variable_tableau.
Cette fonctionnalité est rendue possible par la différentiation explicite entre variables scalaires ($) et variables de liste (@ ou %).
Substitutions
L'exemple précédent introduit la notion de substitution. Cette notion est récupérée de la syntaxe du Korn shell Unix. Toute variable peut se substituer par sa valeur lorsqu'elle est insérée dans une chaîne de caractères entre double cotes.
Exemple :
#!/bin/perl
$variable = "je suis une variable" ;
print("qui est tu ?\n $variable");
qui est tu ?
je suis une variable
Les structures de données
Il existe quatre structures de données majeures en Perl. Ces structures sont :
- les variables scalaires, numériques ou caractères
- les listes, semblables aux énumérations du C
- les tableaux, tels qu'on les retrouve en C
- les tableaux associatifs
Les principales caractéristiques de ces structures de données sont :
- l'auto allocation de mémoire
- le typage implicite par première affectation
- Les variables scalaires numériques sont toutes traitées comme des nombres à virgule flottante, même si leur première définition est entière.
Les variables scalaires ($)
Une variable scalaire est une variable à 0 dimensions, contenant un nombre numérique ou une chaîne de caractères. Son nom symbolique doit toujours être précédé du caractère "$".
Affectation de constantes entières
#!/bin/perl
$var1 = 123 ;
$var2 = -18 ;
$var3 = 1_000_000 ;
$var4 = 047 ;
$var5 = 0x4F ;
Dans l'exemple ci-dessus, $var4 est exprimée sous une notation octale, comme indiqué par le 0 écrit en tête du nombre, et $var5 est exprimée sous sa notation hexadécimale comme l'indique le préfixe "0x" couramment utilisé dans les autres langages tels que le C.
Affectation de constantes à virgule flottante
#!/bin/perl
$var1 = 12.3 ;
$var2 = -0.4 ;
$var3 = 1.34e+8 ;
$var4 = 1.34e-8 ;
L'utilisation d'une arithmétique à virgule flottante devra nécessairement conduire à prendre en compte la possibilité d'une erreur d'arrondi.
Affectation de chaînes de caractères à une variable scalaire
Le Perl permet indistinctement à une variable scalaire d'accueillir un nombre ou une chaîne de caractères. Ces chaînes de caractères, contrairement au C, ne sont pas terminées par un NULL caché. Le caractère NULL peut donc apparaître à tout endroit d'une chaîne.
#!/bin/perl
$var1 = "une chaîne sans null" ;
$var2 = "une chaîne avec \000 null" ;
Types de chaînes en Perl
Le Perl connaît deux écritures de chaînes, encadrées respectivement par des apostrophes ('), ou des guillemets ("). L'interprétation de ces chaînes est très proche de celle faite par le shell Unix :
- Chaînes à guillemets "..."
La chaîne à guillemets autorise la substitution des variables et accepte les séquences d'échappement (de type C) :
#!/bin/perl
$var1 = "variables" ;
$var2 = "ceci est une chaîne qui substitue les $var1\net interprète les caractères d'échappement" ;
print ($var2 );
ceci est une chaîne qui substitue les variables
et interprète les caractères d'échappement
Le caractère permettant l'affichage de symboles non imprimables ou les propres guillemets est l'antislash (\) :
#!/bin/perl
$var1 = "\\ \"" ; # un antislash, un espace et un guillemet
$var2 = "\377" ; # caractère EOF ou 255
$var3 = "\xff" ; # toujours le caractère EOF, en hexadécimal
Note concernant les substitutions :
Les substitutions se font sans problème lorsque l'identificateur est sans ambiguïté. Le problème peut se poser dans le cas où plusieurs identificateurs ont la même racine :
Exemple :
#!/bin/perl
$var = "235" ; # première variable
$var1 = "\n" ; # variable dérivée
L'écriture suivante :
open (FILE, ">monfichier" ;
print FILE ("$var$var1") ;
close (FILE) ;
crée bien un fichier "monfichier" d'une seule ligne contenant la chaîne '2', '3' et '5', puis un "newline" comme l'on pourrait s'y attendre. Le problème se pose lorsque l'on utilise la substitution dans le cas précédent pour écrire $var, immédiatement suivi du chiffre 1 (pour écrire le nombre 2351). L'interpréteur reconnaît un nom symbolique aussi loin qu'il peut aller. L'écriture "$var1" ne peut donc permettre de concaténer la variable $var avec le chiffre 1. On utilisera alors l'écriture ${var}1, qui permet d'arrêter l'interprétation de la variable à substituer au contenu des accolades.
- Chaînes à apostrophes '...'
La chaîne à apostrophe désactive toute substitution, ainsi que l'interprétation des séquences d'échappement à deux exceptions près :
#!/bin/perl
$var1 = "variables" ;
$var2 = 'ceci est une chaîne qui ne substitue pas les $var1\net n\'interprète pas les caractères d\'échappement' ;
print ($var2 );
ceci est une chaîne qui ne substitue pas les $var1\net n'interprète pas les caractères d'échappement
L'exemple précédent montre une des exceptions avec l'apostrophe elle même que l'on pourra insérer dans la chaîne par l'écriture \' ; de même un antislash pourra être inséré par l'écriture \\. En ce sens, ces deux exceptions diffèrent de la syntaxe Unix.
- Chaînes interprétées `...`
La chaîne interprétée est un cas particulier de chaînes en Perl. En fait il ne s'agit pas réellement d'une chaîne, mais de la redirection de la sortie standard STDOUT d'une commande système. La chaîne contenue à l'intérieur des apostrophes inversées doit être interprétable par le système d'exploitation. A l'exécution, l'interpréteur Perl fera exécuter la commande système contenue dans la chaîne et récupérera sa sortie standard. Cette sortie peut être interprétée comme une simple chaîne de caractère multiligne si elle est affectée à une variable scalaire, ou une liste si elle est affectée à une variable de type tableau.
$ls -l
crwxr-xr-x vf 1234 profs /home1/profs/vf/fichier1
crwxr-xr-x vf 254 profs /home1/profs/vf/fichier2
#!/bin/perl
$var1 = `ls -l` ;
@var2 = `ls -l` ;
print "$var1\n" ;
print 'premier élément du tableau $var2\n' ;
print $var2[0] ;
crwxr-xr-x vf 1234 profs /home1/profs/vf/fichier1
crwxr-xr-x vf 254 profs /home1/profs/vf/fichier2
premier élément du tableau $var2
crwxr-xr-x vf 1234 profs /home1/profs/vf/fichier1_
Note : attention, la deuxième affectation ne produit pas deux éléments de tableau si la variable prédéfinie $/ a été redéfinie (voir variables globales prédéfinies)
.Note 2 : Toutes les commandes système ne sont pas forcément exploitable par cette méthode de redirection.
Les listes
Une liste en Perl est l'association en séquence d'un certain nombre de variables scalaires, dans un certain ordre. Ces listes n'ont pas d'existence physique en tant que telles, mais peuvent par la suite être rangées sous forme d'une variable tableau, ou d'un tableau associatif.
Notez qu'une liste peut réunir des données de tous types (nombres, chaînes), y compris des variables, auquel cas la valeur de l'élément de liste prend la valeur de la variable au moment où la liste est interprétée.
Les tableaux (@)
L'utilisation de tableaux est identique à celle de la plupart des langages structurés. Leur fonction consiste à réunir des éléments de même nature dans une table indexée par un "index" numérique. En Perl, l'absence de typage permet de construire des tableaux hétérogènes, contenant indistinctement des valeurs numériques ou des chaînes de caractère. Un tableau en Perl est toujours utilisé en faisant précéder son identificateur du caractère @. Chaque membre d'un tableau est un variable scalaire portant le même nom que le tableau lui-même et donc précédé du caractère $ et suivi de l'index :
#!/bin/perl
$sub = "substituée\n" ;
@tableau = (1, 2.35, "une chaîne\n", "une chaîne $sub") ;
print ("$tableau[0]\n") ;
print ($tableau[3]) ;
1
une chaîne substituée
_
- Gestion des indices
Ce paragraphe définit les différents comportements d'un tableau lorsque des indices "hors gamme" sont utilisés.
- Accès pas un indice hors gamme
Lorsqu'un indice hors gamme est utilisé dans une lecture sur un tableau, le tableau renvoie la chaîne vide. Dans l'exemple ci-dessus, les expressions $tableau[6] ou $tableau[-2] renvoient une chaîne vide.
- Affectation par un indice hors gamme
Lorsqu'on affecte une variable à une case hors gamme du tableau, le Perl étend automatiquement l'allocation du tableau, en copiant la valeur à l'index précisé, et en complétant les index intermédiaires par des variables vides :
#!/bin/perl
@tableau = (1, 2.35, 24, 10e3) ;
$tableau[6] = 18 ;
foreach $case (@tableau)
{
print ("$case\n") ;
}
1
2.35
24
1000
18
_
L'exemple précédent imprime deux chaînes vides, car le tableau est alors défini comme (1, 2.35, 24, 10e3, "", "", 18).
Les tableaux associatifs (%)
Les tableaux associatifs ont la même fonction que les tableaux indexés. La grande différence cependant est le mode d'indexage du tableau. L'index utilisé dans les tableaux associatifs est une chaîne de caractère. Ils permettent donc "d'associer" n'importe quelle valeur à une chaîne, par exemple la chaîne "rouge" à la chaîne "couleur" dans un tableau %objet_3D qui définirait les caractéristiques d'un volume. L'accès à une variable contenue dans un tableau associatif se fait par une variable scalaire du même nom que le tableau indexées par une chaîne contenue dans une expression {}.
#!/bin/perl
$objet_3D{"couleur"} = "rouge" ;
$objet_3D{"forme"} = "cube" ;
$objet_3D{"x"} = 1.27 ;
$objet_3D{"y"} = 2.54 ;
foreach $membre (%objet_3D)
{
print("$objet_3D{$membre}\n") ;
}
rouge
cube
1.27
2.54
_
Chaque nouvelle affectation d'une association redimensionne l'allocation du tableau automatiquement. L'interpréteur Perl se charge de l'opération. Notez qu'une affectation à la chaîne vide "" ou à 0 crée quand même l'association.
Pour savoir si une association existe, on utilisera la fonction intégrée exists(). En voici un exemple à partir de l'exemple précédent. On notera l'utilisation de la fonction delete(), seule façon de supprimer une association existante :
#!/bin/perl
$membre1 = "couleur" ;
$membre2 = "forme" ;
$membre3 = "x" ;
$membre4 = "y" ;
$objet_3D{$membre1} = "rouge" ;
$objet_3D{$membre2} = "cube" ;
$objet_3D{$membre3} = 1.27 ;
$objet_3D{$membre4} = 2.54 ;
@CLEFS = keys(%objet_3D);
delete( $objet_3D{"forme"});
foreach $clef (@CLEFS)
{
print("le membre \"$clef\" n'existe plus") unless exists( $objet_3D{$clef}) ;
};
le membre "forme" n'existe plus_
Les opérateurs
L'essentiel des opérateurs utilisés en Perl est dérivé des opérateurs du C. On trouve en Perl quelques opérateurs supplémentaires destinés au traitement des chaînes de caractère.
Opérateurs arithmétiques
Les opérateurs arithmétiques de base sont identiques au C :
|
+ addition |
- soustraction |
* multiplication |
/ division |
|
% modulo |
- négation unaire |
|
|
Opérateurs supplémentaires
|
** exponentiation |
|
Opérateurs de comparaison
Les opérateurs de comparaison ont été doublés du fait de l'indifférenciation scalaire/chaînes. Le Perl récupère les opérateurs de comparaison numériques du C, et ajoute les opérateurs interprétant les variables comme des chaînes.
Comparaison scalaire entière
Les opérateurs suivants considèrent les variables selon leur interprétation numérique.
|
== est égal à |
!= n'est pas égal |
> est supérieur à |
< est inférieur à |
|
>= est supérieur ou égal |
<= est inférieur ou égal |
|
|
Opérateur non C :
|
<=> comparateur (retourne 1, 0 ou -1) |
|
Comparaison de chaînes
En Perl, chaque opérateur de comparaison numérique a son équivalent pour les chaînes de caractères :
|
eq est égal à |
ne n'est pas égal |
gt est supérieur à |
lt est inférieur à |
|
ge est supérieur ou égal |
le est inférieur ou égal |
|
|
|
cmp comparateur (retourne 1, 0 ou -1) |
|
Comparaison scalaire non entière
Les opérateurs de comparaison numérique sont à manipuler avec précaution dès lors que les variables contiennent des nombres à virgule flottante. En effet on peut se heurter rapidement à des erreurs d'arrondi :
#!/bin/perl
$var1 = 100 + 14.6 - 100 ;
$var2 = 14.6 ;
if ($var1 == $var2) ;
{
print ("pas d'erreur d'arrondi") ;
}
else
{
print ("erreur d'arrondi");
}
Dans l'exemple précédent, le test d'égalité n'est pas rempli, bien que les deux expressions donnent en principe la même valeur.
C'est le traitement d'arrondi de l'interpréteur Perl qui en est la cause : $var1 vaut effectivement 14.60000001, $var2 vaut en réalité 14.59999998. L'égalité exacte n'est pas vérifiée.
Opérateurs logiques
Les opérateurs logiques de base du Perl sont issus du C :
|
&& et logique |
|| ou logique |
! négation logique |
|
La version 5 de Perl admet une autre écriture de ces opérateurs :
|
and et logique |
or ou logique |
not négation logique |
xor ou exclusif |
Opérateurs binaires
Les opérateurs binaires (au niveau bit) sont issus du C :
|
& et binaire |
| ou binaire |
^ ou exclusif binaire |
- complément à 1 |
|
<< décalage vers la droite |
>> décalage vers la gauche |
|
|
Opérateurs d’affectation
Comme en C, la plupart des opérateurs arithmétiques et binaires peut se combiner avec l'opérateur '=' pour combiner une opération et une affectation sur une variable.
|
+= incrémentation |
-= décrémentation |
*= multiplication |
/= division |
|
%= modulo |
&= et binaire |
|= ou binaire |
^= ou excl binaire |
Pour tout opérateur #= de ce type, l'écriture perl ' $a #= $b ' signifie ' $a = $a # $b '.
Opérateurs d’incrémentation décrémentation
Le Perl récupère du C les deux opérateurs d'incrémentation et décrémentation par 1.
|
++$i pré-incrémentation sur $i |
$i++ post-incrémentationsur $i |
--$i pré-décrémentationsur $i |
$i-- post-décrémentationsur $i |
Opérateurs de chaînes de caractères
Le Perl rajoute au C deux opérateurs qui concernent les chaînes de caractères, concept inconnu du C :
L'opérateur de concaténation de chaîne '.'
Les chaînes étant reconnues comme étant un type de base du Perl, il est possible de les concaténer par l'opérateur '.':
#!/bin/perl
$var1 = "je suis " ;
$var2 = "une chaîne\n" ;
$var3 = $var1 . $var2 ;
print ("$var3") ;
Je suis une chaîne
_
L'opérateur de répétition de chaîne x (le caractère x)
L'opérateur x répète plusieurs fois la chaîne en la concaténant:
#!/bin/perl
$var1 = "je." ;
$var2 = $var1 x 3 ;
print ("$var2") ;
Je.Je.Je._
Les structures de contrôle
L'essentiel des structures de contrôle est commun à l'ensemble des langages structurés. Le Perl apporte quelques enrichissements à la syntaxe habituelle en en permettant une lecture plus proche du langage commun.
De plus, le Perl autorise un renversement de la position des éléments dans l'écriture d'une structure.
Toutes les structures de contrôle utilisent une "condition" pour tester si elles doivent exécuter ou ne pas exécuter une séquence de code. Ces conditions peuvent être toute expression valide composée de variables, d'appels de fonctions, d'opérateurs logiques, arithmétiques et d'opérateurs de comparaison.
Instructions conditionnelles
if condition {bloc1} else {bloc2}
Cette expression est classique en langage structuré et exécute la séquence de code "bloc1" si la "condition" est vraie, sinon elle exécute la séquence "bloc2".
{bloc} unless condition
C'est une variante de la précédente qui revient à dire que le "bloc1" précédent ne fait rien. La séquence "bloc" est exécutée sauf si la condition est vraie.
Les boucles
while condition {bloc}
La séquence "bloc" est exécutée tant que la "condition" est vraie. La condition est testée avant la première exécution du bloc, ce qui revient à dire que le bloc peut être sauté si la condition est fausse dès le début. La sémantique de cette boucle est équivalente à "exécuté au moins 0 fois".
do {bloc} while condition
Comme précédemment, la séquence "bloc" est exécutée tant que la "condition" est vraie. La condition est testée après la première exécution du bloc, ce qui revient à dire que le bloc est au moins exécuté une fois.
untill condition {bloc}
Cette structure est en fait l'inverse de la précédente : la séquence "bloc" est exécutée jusqu'à ce que la "condition" soit vraie. SI la condition est vraie dès le départ, la séquence n'est pas exécutée. (Elle est équivalente à l'écriture :
while !condition {bloc}.
do {bloc} until condition
Même version : la séquence "bloc" est exécutée jusqu'à ce que la "condition" soit vraie. Cette écriture fait que la séquence est au moins exécutée une fois. (Elle est équivalente à l'écriture :
do {bloc} while !condition.
for (initialisation ; condition ; itération ) {bloc}
Cette structure, bien connue des programmeurs C exécute un certain nombre de fois la séquence "bloc". Ce nombre de fois est calculé à l'aide d'une variable de boucle initialisée par l'expression "initialisation", testée avant chaque exécution par l'expression "condition", et en général modifiée après exécution de la boucle par l'expression "itération". Les trois expressions "initialisation", "condition" et "itération" pouvant être n'importe quelle expression ou instruction valide, l'utilisation de la boucle for peut souvent dépasser la simple sémantique qui est exposée ici.
foreach $element ( @ensemble) {bloc}
La gestion automatique des listes faites par Perl a permis d'établir une structure de contrôle supplémentaire. Celle-ci exécute la séquence "bloc" en attribuant successivement à la variable $element chacune des valeurs contenues dans @ensemble. La boucle est exécutée autant de fois que le nombre d'éléments que contient la liste @ensemble.
Instructions de rupture de séquence
Le Perl accepte dans toute structure de boucle trois instructions qui "cassent" le déroulement normal d'une structure :
Last
Lorsque l'interpréteur rencontre le mot-clef last, il sort définitivement de la boucle en sautant à la première instruction qui suit la structure.
Next
Lorsque l'interpréteur rencontre le mot-clef next, il sort de la boucle en cours d'exécution et se branche à la fin du bloc de boucle pour commencer la passe suivante (après avoir testé la condition).
Redo
Lorsque l'interpréteur rencontre le mot-clef redo, il arrête le traitement de la boucle en cours et réexécute cette même passe (sans tester de nouveau la condition).
L'utilisation de modèles
Les modèles en Perl
Définition
L'usage de modèles est constant dans les programmes Perl. Les fonctions qui y sont associées permettent une écriture puissante et rapide d'opérations sur les chaînes de caractères qui nécessiteraient l'écriture de nombreuses procédures C. Un modèle est une séquence de caractères et de métacaractères, définissant un modèle de comparaison utilisé par les opérateurs de recherche. Le jeu des métacaractères permet de réaliser des modèles complexes avec de nombreux choix d'options.
En Perl le modèle est aussi appelé expression régulière.
Quelques règles de base :
- Tout métacaractère que l'on a besoin d'utiliser en tant que caractère simple doit être précédé du caractère d'échappement habituel '\'.
- Les délimiteurs de modèle peuvent être remplacés accessoirement par d'autres délimiteurs lorsque le délimiteur standard / est utilisé en tant que caractère dans le modèle.
- Les modèles du Perl s'inspirent très fortement de la syntaxe des modèles utilisés par la fonction awk d'Unix.
Métacaractères dans les modèles
Les métacaractères dans les modèles peuvent être combinés pour arriver à des signification complexes. Ils sont répartis selon deux groupes :
- Les marqueurs de choix
Les marqueurs de choix permettent d'introduire dans les modèles des séquences admettant des solutions multiples. Ils permettent de définir le choix de séquences de caractères qui seront reconnues.
|
+ une occurrence au moins du caractère précédent |
|
* zéro ou plus occurrences du caractère précédent |
|
. un caractère quelconque excepté \n |
|
? zéro ou une occurrence du caractère précédent |
|
{ } spécifie un nombre précis d'occurrences (voir exemples) |
|
[ ] un ensemble de caractères au choix contenu entre les crochets |
|
- à l'intérieur d'un ensemble [ ], permet de spécifier une plage consécutive de caractères |
|
^ à l'intérieur d'un ensemble [ ], exclut l'ensemble mentionné (négation) |
|
| une alternative entre deux modèles différents |
Exemples de quelques combinaisons souvent utilisées :
.* une ligne de caractères quelconques y compris la ligne vide
[a-z] toute lettre minuscule
[A-Z] toute lettre majuscule
[0-9] tout chiffre (digit)
[a-fA-F0-9] tout chiffre hexadécimal
[0-9]+ toute séquence numérique d'au moins un chiffre
de{3}f un 'd', trois 'e' et un 'f'
de{3,}f un 'd', au moins 3 'e', et un 'f'
de{3,5}f un 'd', entre 3 et 5 'e', et un 'f'
Le Perl utilise certaines séquences d'échappement dans les modèles pour désigner des ensembles prédéterminés :
|
\w tout caractère alphanumérique plus _ (habituellement utilisés pour écrire un mot) |
|
\W tout caractère autre que les précédents |
|
\s tout espace |
|
\S tout sauf l'espace |
|
\d tout digit (0 à 9, équivaut à [0-9] |
|
\D tout sauf un digit, équivaut à [^0-9] |
- les ancres
Les ancres permettent de déterminer à quelle position le schème reconnu est valide. Les deux ancres courantes ^ et $ du shell Unix sont bien sûr reconnues.
|
^ reconnaissance en début de ligne |
|
$ reconnaissance en fin de ligne |
Le Perl reconnaît aussi deux ancres exprimées sous formes de séquences d'échappement :
|
\b reconnaissance en bord de mot |
|
\B reconnaissance à l'intérieur du mot (assimilable à !\b) |
Ces deux ancres se placent avant ou après l'expression du modèle suivant que l'on cherche en début ou en fin de mot (ou "non" début, ou "non" fin de mot pour \B).
Définition et utilisation de sous modèles
La syntaxe des modèles de Perl permet de définir des sous-modèles encadrés de parenthèses. Ces sous-modèles un fois exprimés peuvent être réutilisés dans la suite du modèle en appelant chaque sous modèle par la séquence \n (n étant l'ordre de déclaration du sous modèle).
Exemple :
/([\da_z]+)([:;])\1\2\1/
L'exemple précédent défini un sous modèle 1 recherchant toute séquence de nombres et de lettres minuscules. Le sous modèle 2 recherche une occurrence d'un point-virgule ou d'un deux-points. Le modèle complet cherchera une séquence composée :
- d'une chaîne alphanumérique minuscule,
- d'un point-virgule ou d'un deux-points,
- de la chaîne alphanumérique minuscule trouvée au premier,
- d'un deux-points ou un point-virgule (selon celui trouvé au deuxième),
- une dernière chaîne alphanumérique minuscule identique à celle du premier.
Notez que cette mémorisation des modèles n'est que de courte durée. Dès la fin de l'instruction qui utilise le modèle, le Perl "oublie" les sous-modèles qu'il a mémorisé.
Important : ce qui est stocké dans la mémoire est le premier résultat trouvé pour le sous-modèle, et non l'expression de recherche. Une fois qu'un morceau de chaîne correspond au sous modèle entre parenthèses, ce morceau est mémorisé et réutilisé lors de l'appel par \.
Récupération des variables trouvées par le modèle
Lorsque l'on définit un sous modèle, il est intéressant de pouvoir extraire la chaîne trouvée lui correspondant. Le Perl utilise pour cela un mécanisme d'Unix qui fait appel aux variables prédéfinies $1, $2, etc.
Chaque fois que le sous modèle \1 est trouvé, la variable $1 contient la chaîne correspondante, $2 la chaîne correspondant au sous-modèle \2, et ainsi de suite :
$ cat > unfichier
ceci est un fichier test
^D
$
#!/bin/perl
if open (FILE, "unfichier") ;
$var = <FILE> ;
close(FILE) ;
$var =~ /(\b.*)(\b.*)(\b.*)(\b.*)/ ;
print "$1\n" ;
print "$2\n" ;
print "$3\n" ;
print "$4\n" ;
ceci
est
un
fichier
_
Cette possibilité rend possible des fonctions d'extraction de données très puissantes dans des fichiers de données tels des fichiers systèmes Unix, ou des bases de données plates.
Note : la variable prédéfinie $& stocke le résultat de concordance du modèle entier.
Les opérateurs de recherche et de traitement de chaînes en Perl
Les opérateurs =~ et !~ de recherche
Les opérateurs spéciaux de recherche de modèle =~ et !~ effectuent une recherche de modèle dans la variable placée à gauche. Dans un contexte scalaire, l'ensemble de l'expression renvoie une valeur booléenne suivant l'opérateur et suivant que le modèle a été trouvé ou non. Dans un contexte de liste (encore appelé vectoriel), l'ensemble de l'opération renvoie une liste contenant tous les sous-modèles trouvés si des sous-modèles ont été définis, ou la liste (1) (équivaut à (vrai)) si le modèle est en un seul bloc et l'option /g n'est pas activée.
L'opérateur de recherche admet plusieurs options qui sont spécifiées juste après le modèle :
Exemple :
$var =~ /[^abc]/xgimos
Les options admises sont
|
x |
ignore les espaces blancs dans la chaîne de modèle |
|
g |
recherche tous les modèles possibles |
|
i |
ignore la casse |
|
m |
traite une chaîne comme des lignes multiples |
|
o |
évalue une seule fois le modèle |
|
s |
traite la chaîne comme une seule ligne |
OPTION X
Les espaces blancs sont ignorés dans le modèle, ainsi les modèles :
/abc/
et
/ a b c /
sont équivalents, et recherchent tous deux une occurrence de la chaîne "abc".
OPTION G
Recherche tous les modèles possibles. Cette fonction permet, associée à une affectation scalaire, de balayer la chaîne source pour trouver successivement les différentes correspondances.
Exemple :
$var = "Tchaikovski, tchekov, tchetchene";
While ($var =~ /Tch.+ov\w+/ig;
{
$trouve = $&;
print ("$trouve\n");
}
Tchaikovski
tchekov
L'exemple précédent montre comment l'option g permet, dans une boucle de rechercher tous els mots contenant au moins un schéma commençant par "tch" puis contenant le schéma "ov" dans la suite.
Note : L'option i utilisée ici permet de plus de ne pas tenir compte de la casse, et permet de recueillir les mots commençant par T aussi bien que t.
OPTION I
(voir ci-avant)
OPTION M
Cette option est à utiliser lorsque la variable chaîne de caractère comporte des caractères \n (fin de ligne) à un autre emplacement que la fin de chaîne. Cette option précise que la chaîne contenue dans la variable contient plusieurs lignes.
Cela influe par exemple sur l'utilisation de l'ancre ^, qui sera évaluée derrière chaque occurrence du caractère \n dans la chaîne.
OPTION O
Evalue la valeur du modèle à rechercher qu'une fois et fixe sa valeur pour la recherche d'occurrences suivantes.
OPTION S
Cette option est à utiliser lorsque la variable chaîne de caractère comporte des caractères \n (fin de ligne) à un autre emplacement que la fin de chaîne. Cette option force la fonction de recherche de poursuivre la recherche jusqu'à la fin de la chaîne, sans considérer le caractère \n comme une fin de ligne.
L'opérateur de substitution =~ s/modèle/substituant/
L'opérateur de substitution (aussi appelé substitution globale, par rapport à la substitution caractère par caractère - cf. translation) permet de remplacer toutes ou parties des occurrences d'un modèle par une chaîne substituante, constante ou variable.
Le modèle doit être une expression régulière du Perl
Le substituant peut être une chaîne constante ou une chaîne ou sont substituées des variables. Par exemple, l'expression suivante :
$var =~ s/(^\w+)\s+(\w+)/$2 $1/;
Inverse les deux premiers mots d'une chaîne contenue dans la variable $var, et comprime éventuellement les espaces entre ces deux mots.
A noter que le substituant est une véritable chaîne de caractères, et que les métacaractères présents dans celle-ci perdent leur signification spéciale.
La fonction de substitution globale admet elle aussi des options, ajoutées en fin d'instruction :
|
x |
ignore les espaces blancs dans la chaîne de modèle |
|
g |
recherche tous les modèles possibles |
|
i |
ignore la casse |
|
m |
traite une chaîne comme des lignes multiples |
|
o |
évalue une seule fois le modèle |
|
s |
traite la chaîne comme une seule ligne |
|
e |
traite la chaîne comme une seule ligne |
L'opérateur de translation =~ tr/liste_caractères/translation/
L'opérateur de translation est une autre forme de substitution par Perl dans des variables texte. La différence est ici que la substitution s'effectue caractère par caractère, utilisant une "table" de transcription définie par la correspondance entre la liste de caractères et le substituant.
La liste de caractères à substituer et la "translation" n'ont pas nécessairement la même taille. Trois cas sont possibles :
1 - La liste à substituer est de même longueur que la chaîne de substitution
Dans ce cas, la correspondance se fait naturellement en suivant l'ordre des caractères un à un.
$chaîne = "bacd";
$chaîne =~ tr/abcd/fdes/;
print $chaîne;
dfes
2 - La liste à substituer est plus longue que la chaîne de translation.
Dans ce cas, c'est le dernier caractère de la chaîne de translation qui sera considéré comme le caractère d'arrivée de tous les caractères "en trop" de la liste de caractères :
$chaîne = "abcd";
$chaîne =~ tr/abcd/fde/;
print $chaîne;
fdee
on remarque que les deux lettres 'c' et 'd' ont toutes deux été "translatées" vers le caractère 'e'.
3 - La liste à substituer est plus courte que la chaîne de translation.
La transcription est faite dans l'ordre un à un des caractères, les caractères "en trop" du subtituant étant ignorés.
Cas de caractères dupliqués
Les caractères mentionnés dans les deux chaînes caractérisant l'opération de transcription ne sont pas nécessairement uniques. Si des caractères sont dupliqués dans la liste à substituer alors seule la première correspondance sera considérée (injection), ainsi, dans :
tr/abbd/fdeg/;
le caractère 'b' ne pourra être substitué que par 'd' (2ème rang). L'affectation 'b' vers 'e' étant inopérante (3ème rang)
Si des caractères sont dupliqués dans le substituant, alors plusieurs caractères de départ seront substitués en un même caractère d'arrivée (surjection).
L'exemple
tr/\t\r\n/@@@/;
Transforme tous les caractères spéciaux "tabulation", "retour chariot" et "retour ligne" en '@'.
La fonction de translation admet trois options, ajoutées en fin d'instruction :
|
c |
Transcrit tous les caractères autres que ceux de la liste à substituer. Ex : tr /\d/ /c;(transcrit tous les caractères autres que des digits en espaces) |
|
d |
supprime tous les caractères présents dans la liste à substituer le substituant n'est plus mentionné, Ex. : tr /\t\r/d;(supprime tous les caractères "tabulation" et "retour chariot") |
|
s |
(de squeeze) compresse les ensembles de caractères identiques obtenus lors d'une surjection |
Entrées sorties dans des fichiers
Toute application, script, ou utilitaire aura nécessairement à lire et écrire dans des fichiers. Le cgi-bin le plus simple aura au minimum à lire et écrire dans deux fichier spéciaux définis par STDIN et STDOUT, et constituant deux des trois flux standards de toute tâche en exécution (le troisième étant le flux d'erreur STDERR).
Avant tout accès à un fichier, et pour éviter toute erreur intempestive du cgi et l'arrêt inopiné de celui-ci, il sera presque toujours utile de vérifier l'existence ou la disponibilité des fichiers utilisés par le script. Le Perl donne des possibilités très étendues d'accès aux informations du système de fichiers de sa plate-forme hôte.
Gestion de fichiers
Tests sur les propriétés des fichiers
Suivant le système d'exploitation, les fichiers disposent d'un certain type de structure d'information réunissant des indicateurs d'état sur le fichier examiné. Les opérateurs de test suivantes s'appuient sur la structure d'information d'un système de fichiers UNIX :
La syntaxe générale de ces test est :
-@ nom
|
-b |
nom est-il constitué d'un bloc ? |
|
-c |
nom est-il constitué de caractères ? |
|
-d |
nom est-il un répertoire ? |
|
-e |
nom existe t'il ? |
|
-f |
nom est-il un fichier d'archives ordinaire ? |
|
-g |
Le bit setgid de nom est-il positionné ? |
|
-k |
Le "sticky bit" de nom est-il positionné ? |
|
-l |
nom est-il un lien symbolique ? |
|
-o |
nom appartient-il à l'utilisateur* ? |
|
-p |
nom est-il un nom de canal (pipe) ? |
|
-r |
nom est-il autorisé en lecture* ? |
|
-s |
nom est-il un fichier non vide ? |
|
-t |
nom est-il un fichier de terminal ? |
|
-u |
Le bit setuid de nom est-il positionné ? |
|
-w |
nom est-il autorisé en écriture* ? |
|
-x |
nom est-il autorisé en exécution* ? |
|
-z |
nom est-il un fichier vide ? |
|
-A |
Quelle est la date du dernier accès à nom ? |
|
-B |
nom est-il un fichier binaire ? |
|
-M |
Quand nom a-t'il été modifié pour la dernière fois ? |
|
-S |
nom est-il un socket ? |
|
-T |
nom est-il un fichier texte ? |
*ici, l'utilisateur est en fait celui à qui appartient le script Perl qui teste ces conditions.
Fonctions de manipulation de fichiers et répertoires
Les fonctions de manipulation permettent d'effectuer un certain nombre d'opérations sur les fichiers "de l'extérieur", comme leur listage, déplacement, renommage, suppression, etc. Toutes ces fonctions ne supposent pas l'ouverture du fichier lui-même, mais effectuent des appels système pour effectuer l'opération demandée.
Les répertoires peuvent, selon la philosophie UNIX, être ouverts, lus ou manipulés comme tout autre fichier :
|
mkdir |
(nom_rép, protection) |
crée un répertoire (à partir du répertoire courant) |
|
chdir |
(nom_rép) |
change le répertoire courant |
|
opendir |
(identificateur, nom_rép) |
Ouvre un répertoire pour lecture |
|
readdir |
(identificateur) |
Lit l'entrée suivante d'un répertoire |
|
telldir |
(identificateur) |
renvoie la position actuelle de lecture dans le répertoire |
|
seekdir |
(identificateur, position) |
déplace la position courante de lecture à la nouvelle position indiquée. S'utilise en général par décalage relatif par rapport au résultat donné par telldir. |
|
rewinddir |
(identificateur) |
Renvoie la position courante de lecture au début du répertoire. |
|
closedir |
(identificateur) |
Ferme le répertoire ouvert pour l'identificateur. |
|
rmdir |
(nom_rép) |
Détruit le répertoire si celui-ci est vide. |
Il existe une méthode alternative, dans certains cas, pour effectuer une lecture de répertoire : En effet, l'utilisation de la "capture de commande système" par la syntaxe :
@REPERTOIRE = `dir` # DOS
@REPERTOIRE = `ls -a` # UNIX
fonctionne parfaitement (en fait cette méthode ne fonctionne qu'avec les commandes système qui retournent un résultat non vide). Cette méthode alternative permet d'exploiter un répertoire comme un tableau, et de l'explorer en interne.
Fonctions d'ouverture et de fermeture
Ouverture et fermeture
En Perl, comme dans la plupart des langages de 3ème génération, la lecture d'information dans des fichiers s'effectue par l'intermédiaire d'un flux nommé. Ce flux représente en fait un pointeur de lecture et/ou écriture pointant à un endroit spécifique d'un fichier.
Pour établir ce flux, on ouvrira le fichier par le commande open, à laquelle sera donné un nom de flux, et le nom d'un fichier à ouvrir :
#!/bin/perl
open (FICHIER, "nom_de_fichier.txt");
Une fois ce flux créé, les données deviennent accessible par lecture séquentielle dans le fichier.
Après la dernière instruction d'accès aux données, le fichier sera refermé par un appel à la fonction close :
close(FICHIER);
Utilisation du principe de redirection
De par son origine shell très marquée, le Perl exploite au maximum le principe de redirection mis en œuvre sous UNIX.
Dans ce concept, toute commande est un processus qui admet un certain nombre de flux en entrée, un certain nombre de flux en sortie, et des flux d'erreur.
L'opérateur d'accès <>
En Perl, comme dans la plupart des langages de 3ème génération, la lecture d'information dans des fichiers s'effectue par l'intermédiaire d'un flux nommé. Ce flux représente en fait un pointeur de lecture et/ou écriture pointant à un endroit spécifique d'un fichier.
Le Perl fournit une syntaxe simple et puissante de lecture dans un flux. L'opérateur <> permet en effet la lecture de lignes d'un fichier, et son fonctionnement dépend du contexte dans lequel il est utilisé (scalaire, ou liste).
- Contexte scalaire
Lorsque la variable recevant le résultat de lecture est une variable scalaire, l'opérateur <flux> lit une ligne du fichier (le caractère de fin de ligne compris). Le pointeur de fichier pointe alors sur le premier caractère de la ligne suivante en attendant une lecture ultérieure.
$cat >fichier
première ligne
deuxième ligne
troisième ligne
^D
$
#!/bin/perl
open(FLUX, "fichier");
$une_ligne = <FLUX>;
print("premier accès scalaire : $une_ligne");
$une_ligne = <FLUX>;
print("deuxième accès scalaire : $une_ligne");
$une_ligne = <FLUX>;
print("troisième accès scalaire : $une_ligne");
close(FLUX);
premier accès scalaire : première ligne
deuxième accès scalaire : deuxième ligne
troisième accès scalaire : troisième ligne
- Contexte de liste
Dans un contexte de liste (lecture affectée à un tableau @LIGNES), l'opération lit toutes les lignes du fichier jusqu'à la fin du fichier, et crée en mémoire un tableau (ici @LIGNES) image du fichier entier. Soit, en réutilisant le fichier de l'exemple précédent :
#!/bin/perl
open(FLUX, "fichier");
@LIGNES = <FLUX>;
close(FLUX);
print("accès en liste : \n");
$i = 0;
foreach $ligne (@LIGNES)
{
print("LIGNE[$i] : $ligne");
$i++
}
accès en liste :
LIGNE[0] : première ligne
LIGNE[1] : deuxième ligne
LIGNE[2] : troisième ligne
L'opérateur <> utilisé seul (sans descripteur de flux) a une signification particulière. Le premier appel à cette syntaxe ouvre le premier fichier passé dans la ligne de commande de l'appel au Perl (ce fichier est contenu dans la variable prédéfinie $ARGV[0]. La lecture se fait alors séquentiellement et les fichiers suivants dans la ligne de commande ($ARGV[1], $ARGV[2]...) sont successivement ouverts et lus. Cette fonction a peu d'intérêt dans un contexte cgi-bin dans la mesure où le contrôle de la ligne de commande n'est pas direct.
Autres fonctions d'accès et fonctions associées
Lecture caractère par caractère : getc()
La fonction getc(FILE) permet de lire un flux d'entrée ou un fichier caractère par caractère. Elle est en général utilisée pour récupérer des commandes monocaractères et non sous la forme d'un ligne de commande. Dans ce cas les fonctions read ou l'opérateur <FILE> ne peuvent convenir, dans la mesure où ces deux commandes attendent un caractère "fin de ligne" (\n) pour rendre la main au programme. La fonction getc() permet de lire un caractère unique et de traiter directement le caractère obtenu en retour.
Note : Cette fonction est peu utilisable dans un contexte cgi-bin dans la mesure où la console n'est pas l'interface standard d'entrée du programme.
Lecture d'enregistrements : read()
La fonction read(...) est une fonction de lecture assez générale qui peut lire dans un fichier et inscrit la chaîne résultat dans une variable scalaire. Sa syntaxe est similaire à celle d'UNIX ou du C en général :
read(FILE, $variable, Longueur, SkipOption);
Longueur
précise le nombre de caractères à lire à partir de la position courante. SkipOption est un entier permettant de sauter un SkipOption caractères avant de commence la lecture des Longueur caractères.Ecritures : print(), printf(), write()
Ces trois fonctions permettent l'écriture dans un fichier lorsque celui-ci a été ouvert pour l'écriture ou la mise à jour. La fonction print() inscrit la variable passée en argument dans le fichier au point courant d'insertion. Si le fichier a été ouvert en mode écriture (>), ce point d'insertion est par défaut au début du fichier et l'ancienne version du fichier est détruite. Si ce fichier a été ouvert en mise à jour (>>), le point d'insertion est par défaut à la fin du fichier. Toute écriture s'ajoute au contenu du fichier original. La syntaxe de la fonction print() est :
print FILE (liste_arguments);
Si le descripteur de fichier FILE est omis, l'écriture se fait dans STDOUT. C'est cette sortie standard qui sera utilisée pour renvoyer au navigateur client la réponse du cgi-bin.
Printf() et write() sont des version formatées de la fonction print(), c'est à dire qu'elles impriment les arguments selon un format d'affichage programmable. La fonction Printf() est semblable à celle du C de même nom. La fonction write() utilise une variable prédéfinie '$-' pour stocker le format de mise en forme.
Conséquence : Les fonctions read() et write() NE SONT PAS l'inverse l'un de l'autre. Elles sont sémantiquement différentes.
Déplacements dans un fichier : seek(), tell()
Les fonction vues ci-avant effectuent des accès dans des flux. Ceux-ci ont une caractéristique inaltérable : ils représentent des fichiers à accès séquentiel, c'est à dire qu'une lecture fait avancer le point d'insertion-lecture vers l'avant, le fichier n'étant accessible qu'à ce point particulier. La récupération des données se fait donc "en séquence" du début à la fin.
Afin de retrouver un peu de souplesse dans les accès aux données, deux fonctions permettent de générer des déplacements du pointeur d'accès dans le flux.
La fonction seek() permet d'avancer ou de reculer dans le flux d'un certain nombre de caractères, à partir d'un point de départ donné. La syntaxe d'appel de cette fonction est :
seek(FLUX, $distance, $rapport_à)
distance
compte le nombre de caractères du déplacement, vers l'avant si positif, vers l'arrière si négatif; rapport_à donne une position de départ et peut prendre trois valeurs : 0 pour un déplacement à partir du début de fichier, 1 à partir de la position courante, 2 par rapport à la fin du fichier.La fonction tell(FLUX) est la contrepartie de la fonction précédente et indique en octets la position courante du pointeur à partir du début du FLUX spécifié.
Fonctions, procédures et sous-programmes
Appel de fonctions et de sous programmes
Comme tout langage structuré, le Perl permet d'écrire les applications comme un assemblage de "fonctions" ou de "procédures".
Note : La fonction renvoie habituellement une valeur. La procédure exécute un certain nombre d'actions sans rien renvoyer.
La différence fondamentale entre fonction et procédure n'existe pas en Perl. En effet, tout sous-programme Perl renvoie en sortie la valeur de la dernière expression qu'il évalue. De ce fait, le Perl peut envoyer toute structure de données en retour.
Les fonctions peuvent être implémentées avec ou sans paramètres. L'utilisation d'une fonction, ou de sa valeur de retour, se fait en écrivant le nom de la fonction précédé du caractère '&'. Ce caractère permet de respecter la règle de typage explicite du Perl, instaurant ainsi une quatrième classe de variables après les variables scalaires ($), tableau (@), tableau associatif (%), et désormais fonction (&).
#!/bin/perl
&init_script;
Note : on notera que la présence du '&' n'est plus obligatoire lorsque la fonction est implémentée avant son utilisation :
#!/bin/perl
sub &
Implémentation d'une procédure ou d'une fonction
Syntaxe d'implémentation
Le Perl n'impose pas de règle contraignante quant à la position de l'implémentation d'une fonction (contrairement au C, celle-ci peut être écrite après son utilisation). Ceci est rendu possible par un mécanisme de précompilation effectuée par l'interpréteur Perl.
L'implémentation d'une fonction répond à la syntaxe suivante :
sub nom_fonction
{
implémentation...
}
Variables locales, variables globales
Les fonctions Perl peuvent parfois utiliser des variables qui n'ont pas de signification en dehors de leur implémentation. On dit alors que ces variables ont une "portée locale".
Une variable est globale par défaut, à moins que ne soit explicitement indiqué son caractère local par le mot clef "my" placé avant sa première utilisation dans la fonction.
#!/bin/perl
$var_glob = 'ceci est une variable globale';
sub sous_programme
{
my $var_loc = 'ceci est une variable locale';
}
Attention : Lorsqu'une variable locale porte le même nom qu'une variable globale, cette dernière n'est plus accessible lorsque l'on se trouve dans le corps de la fonction. On parle alors de masquage de variable.
Passage de paramètres à une fonction ou procédure
Le passage de paramètre est très souple en Perl. Il ne nécessite pas en effet une précaractérisation précise du "prototype" de la fonction. En effet, tous les paramètres sont passés par l'intermédiaire d'une variable prédéfinie du Perl (Cf. variables spéciales prédéfinies), la variable de liste @_. Un appel à la fonction peut passer n'importe quel nombre de paramètres scalaires ou de listes, qui seront inclus dans la liste @_ avant l'appel. La récupération des paramètres se faisant par l'accès, à l'intérieur de la fonction, à la liste @_ :
#!/bin/perl
($param1, $param2, $param3) = ('un', 234, 'trois');
&sous_programme($param1, $param2, $param3);
sub sous_programme
{
($parm_interne1, $parm_interne2, $parm_interne3) = @_;
...
instuctions
...
}
Valeur retournée par une fonction
Fonctions "built-in"
Pour la description des fonctions standard du Perl, on se reportera au fichier HTML "perlfunc.htm" de la documentation Perl livrée avec l'interpréteur Perl du projet GNU.
Variables prédéfinies
Le Perl définit un certain nombre de variables prédéfinies stockant en permanence le dernier résultat de certaines opérations. Ces variables sont reconnaissables par leur syntaxe particulière, constituée d'un des identificateurs de type Perl suivi d'un symbole texte non alphabétique. Dans la plupart des cas, ces appellations réduites concordent à un nom symbolique développé de ces variables.
$ARG ou $_
L'entrée par défaut et la chaîne de recherche (=~) par défaut. Les paries d'expressions suivantes sont équivalentes :
while (<>) {...} # seulement dans un while!
while ($_ = <>) {...}
/^Sujet:/
$_ =~ /^Sujet:/
tr/a-z/A-Z/
$_ =~ tr/a-z/A-Z/
chop
chop($_)
$MATCH ou $&
La dernière portion de chaîne reconnue par la dernière opération de recherche par le modèle entier (les sous-chaînes trouvées dans un bloc imbriqué ou une syntaxe eval() ne sont pas prises en compte). En lecture seulement.
$PREMATCH ou $`
La portion de chaîne située entre le début de la chaîne de recherche et la dernière sous-chaîne trouvée ($&) (les sous-chaînes trouvées dans un bloc imbriqué ou une syntaxe eval() ne sont pas prises en compte). En lecture seulement.
$POSTMATCH ou $'
La portion de chaîne située la dernière sous-chaîne trouvée ($&) et la fin de la ligne de recherche (les sous-chaînes trouvées dans un bloc imbriqué ou une syntaxe eval() ne sont pas prises en compte). En lecture seulement.
$NR ou $.
Le numéro de ligne courante dernièrement lue sur le flux d'accès courant (<>). En lecture seulement. On notera que seule la fermeture explicite d'un fichier repositionne ce numéro de ligne à 0.
$OUTPUT_AUTOFLUSH ou $|
Si marquée non nulle, force une opération "flush" après chaque "write" ou "print" sur le flux de sortie sélectionné. Vaut 0 par défaut. On rappel que l'opération flush constitue à vider le tampon intermédiaire servant à stocker temporairement les données avant leur écriture définitive dans le fichier physique de sortie.
$OUTPUT_FIELD_SEPARATOR ou $OFS ou $,
Détermine ce qui est imprimé par défaut entre deux éléments d'une liste donnée à la fonction print.
$OUTPUT_RECORD_SEPARATOR ou $ORS ou $\
Détermine ce qui est imprimé par défaut après chaque exécution d'une fonction print. Un exemple courant est d'initialiser cette variable avec le caractère '\n' (retour à la ligne).
$LIST_SEPARATOR ou $"
Détermine le caractère qui sépare les éléments successifs d'une liste ou un tableau lorsque son nom symbolique est substitué dans une chaîne substituante :
#!/bin/perl
$" = ' | ';
@tableau = ( 'un', 'deux', 'trois');
print ("@tableau");
un | deux | trois
$OS_ERROR ou $ERRNO ou $!
Dans un contexte numérique, contient le dernier code d'erreur retourné par le système d'exploitation. (N'a de signification exploitable qu'en cas d'une erreur retournée par un appel système). Utilisé comme une chaîne, donne un accès au texte explicite de l'erreur correspondante.
$PROCESS_ID ou $PID ou $$
Le numéro de processus de l'interpréteur exécutant ce shell (UNIX).
$REAL_USER_ID ou $UID ou $<
L'uid réel de ce processus soit, le propriétaire du script.
$EFFECTIVE_USER_ID ou $EUID ou $>
L'uid effectif du script. (Celui qui l'a lancé).
$REAL_GROUP_ID ou $GID ou $(
Le ou les groupes auquel appartient le script. (C'est en fait la liste des groupes auquel appartient le propriétaire (uid) du script.
$EFFECTIVE_GROUP_ID ou $EGID ou $)
Le ou les groupes effectifs du script (les groupes auxquels appartient l'utilisateur qui l'a lancé).
$ARGV
Contient le nom du fichier courant en lecture par l'opérateur <>.
@ARGV
Le tableau @ARGV contient les arguments passés dans la ligne de commande de lancement du script. Noter que $#ARGV représente le nombre d'arguments moins un, car $ARGV[0] est le premier argument, et nom le nom du script.
@INC
Contient la liste des répertoires où les librairies ou bibliothèques de fonctions pourront être trouvées. (réduction de @INCLUDES)
%INC
Contient la liste des bibliothèques réellement incluses par une syntaxe use, ou require.
$ENV{expr}
Un tableau associatif qui contient une image des variables d'environnement système. La modification d'une variable ENV change l'environnement des processus fils.
$SIG{expr}
Le tableau associatif %SIG gère la mise en œuvre de certains signaux systèmes.