Accueil - Informatique - Programmation - Langages

Perl

Publié le mardi 7 septembre 2004.


Perl est un langage qui permet de manipuler facilement du texte, des fichiers et des processus. Aujourd’hui livré en standard sur la plupart des systèmes d’exploitation. Il s’est progressivement imposé comme le langage de scripts de référence.

Mise à jour : 26 avril 2007

Installation

Perl fonctionne sur de multiples plateformes. Sous Unix ou Linux, pas de difficultés particulières pour l’installation.
Sous Windows, on peut utiliser Perl sous Cygwin comme sous Unix, ou installer la version de Perl ActiveState
.

Les modules

Vérifier si un module est installé

Pour tester si le module Date::Manip est installé et disponible sur votre système, taper la ligne de code suivante :

$ perl -e 'use Date::Manip'

Si le module est présent et correctement installé, pas de message. Dans le cas contraire, vous obtiendrez le message suivant :

$ perl -e 'use Module'
Can't locate Module.pm in @INC (@INC contains: /usr/lib/perl5/5.8/cygwin /usr/lib/perl5/5.8 /usr/lib/perl5/site_perl/5.8/cygwin /usr/lib/perl5/site_perl/5.8 /usr/lib/perl5/site_perl/5.8 /usr/lib/perl5/vendor_perl/5.8/cygwin /usr/lib/perl5/vendor_perl/5.8 /usr/lib/perl5/vendor_perl/5.8 .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

Déterminer la liste des répertoires du tableau @INC

$ perl -e 'for (@INC) {printf "%d %s\n", $i++, $_}'
0 /usr/lib/perl5/5.8.2/cygwin-thread-multi-64int
1 /usr/lib/perl5/5.8.2
2 /usr/lib/perl5/site_perl/5.8.2/cygwin-thread-multi-64int
3 /usr/lib/perl5/site_perl/5.8.2
4 /usr/lib/perl5/site_perl
5 .

Plus simple :

$ perl -V
Summary of my perl5 (revision 5.0 version 8 subversion 2) configuration:
 Platform:
   osname=linux
...
 @INC:
   /usr/lib/perl5/5.8.2/cygwin-thread-multi-64int
   /usr/lib/perl5/5.8.2
   /usr/lib/perl5/site_perl/5.8.2/cygwin-thread-multi-64int
   /usr/lib/perl5/site_perl/5.8.2
   /usr/lib/perl5/site_perl
   .

Installer manuellement un module sous Unix/Cygwin

Récupérer le module sous cpan.org, le décompresser, puis :

$ perl Makefile.PL
ou
$ perl Makefile.PL LIB=~/local/lib

Il faut être root pour installer un module dans le répertoire par défaut de Perl. On peut le compiler et l’installer localement en spécifiant le répertoire de destination comme ci dessous.

$ make
$ make test
$ make install

Installer un module avec CPAN

Pour installer par la suite un module ou un ensemble de modules (bundle) comme par exemple Bundle::LWP :
Bundle::LWP - A bundle to install all libwww-perl related modules

perl -MCPAN -e 'install Bundle::LWP'

Lors de la première utilisation, il faudra répondre manuellement aux questions pour initialiser CPAN. Si vous n’avez pas les droits de root, vous pourrez spécifier un autre répertoire pour l’installation des modules (PREFIX). Par pouvez également spécifier le répertoire d’installation des sources, par défaut : /.cpan. On peut également modifier ces paramètres via le fichier :

C:\cygwin\lib\perl5\5.8.2\CPAN\Config.pm

Sous CPAN, obtenir la configuration actuelle :

cpan> o conf

Modifier la config, exemple :

cpan> o conf urllist push ftp://ftp-u-paris10.fr/perl/CPAN
cpan> o conf shell /bin/bash

Important( cygwin) : Lorsque l’on utilise Perl sous cygwin depuis une machine en réseau dans un domaine NT avec une même « home dir » réseau partageable entre plusieurs machines différentes, il est absolument nécessaire d’installer les modules via CPAN dans un répertoire local à la machine (/home/user/.cpan), sinon, vous aurez des problèmes lors des mise à jour.

J’ai également remarqué des problèmes lors de la compilation de certains modules depuis un répertoire .cpan en réseau (PDL, LWP).

Attention : Lors de changement de version, il peut être nécessaire d’installer de nouveau les modules.

Utiliser pour cela la commande autobundle de CPAN pour faire un cliché de l’installation que l’on pourra utiliser après la mise à jour à partir du répertoire.

Se mettre root puis lancer cpan :

[root@localhost root]# cpan

cpan shell -- CPAN exploration and modules installation (v1.7601)
ReadLine support enabled

cpan> autobundle
CPAN: Storable loaded ok
...
liste des modules ...
...
Wrote bundle file
   /root/.cpan/Bundle/Snapshot_2004_09_07_00.pm

La commande autobundle a généré un fichier que l’on installera sous la nouvelle version de Perl :

# cd /root/.cpan/Bundle
# perl -MCPAN -e 'install Bundle::Snapshot_<date>'

Par défault, j’installe les modules suivants :

perl -MCPAN -e 'install Bundle::LWP'
perl -MCPAN -e 'install Mail::Address'
perl -MCPAN -e 'install Date::Manip'
perl -MCPAN -e 'install DBI'
perl -MCPAN -e 'install DBD::Pg'
perl -MCPAN -e 'install PDL'
perl -MCPAN -e 'install PDL::NetCDF'
perl -MCPAN -e 'install XML::LibXML'
perl -MCPAN -e 'install XML::Simple'
perl -MCPAN -e 'install Statistics::Basic'
perl -MCPAN -e 'install WWW::Mechanize'
perl -MCPAN -e 'install Module ::Starter'

Il pourra être utile de se faire un alias de cpan à mettre dans son fichier ~/.bashrc

alias cpan='perl -MCPAN -e shell'

Si l’installation d’un module sous CPAN échoue, il sera peut être nécessaire de réaliser manuellement son installation via la procédure décrite au paragraphe précédent.

Une lecture attentive des dernières lignes pourra éventuellement vous donner quelques indications. Si l’installation échoue à la suite d’erreurs dans les procédures de tests, on peut forcer l’installation du module :

cpan> force install WWW::Mechanize

On peut également localiser le répertoire d’installation du module sous cpan pour ensuite réaliser manuellement la compilation/installation :

cpan> look WWW::Mechanize
Running look for module WWW::Mechanize

Trying to open a subshell in the build directory...
Working directory is /home/user/.cpan/build/WWW-Mechanize-1.16
cpan> quit
$> cd /home/user/.cpan/build/WWW-Mechanize-1.16
$> perl Makefile.PL
$> make
$> make install

Parfois sous Cygwin, la compilation peut échouer pour d’obscures raisons par toujours évidentes à mettre en évidence (module PDL par exemple).

Si la compilation manuelle décrite ci-dessus échoue, on peut installer les binaires d’un module depuis le site cygwin-port
J’ai installé avec succès via le programme setup.exe depuis un répertoire local les modules suivants :

DBI
PDL
...

Installer un module avec ActiveState

Pour installer un module avec CPAN, utiliser la commande ppm3 depuis une console Windows :

q:> ppm3 install <nom du module>

Installer un module manuellement :

Installer un décompresser le module dans un répertoire.
La procédure est la même que sous Unix mais il faudra utiliser l’utilitaire nmake à la place de make.

Récupérer nmake.
puis par exemple pour compiler et installer le module DateManip :

C:\perl\modules\DateManip-5.39> perl Makefile.PL
C:\perl\modules\DateManip-5.39> nmake
C:\perl\modules\DateManip-5.39> nmake test
C:\perl\modules\DateManip-5.39> nmake install

Concevoir un module

Une distribution est une archive contenant un ou plusieurs modules et les fichiers nécessaires à leur installation. Il existe plusieurs outils permettant de créer automatiquement le squelette d’une distribution.

h2xs

La première possibilité est d’utiliser h2xs qui est present nativement dans Perl. Pour générer l’arborescence minimale d’un module Oceano::Seabird il suffit de taper la ligne suivante dans un shell :

$ h2xs -XA -n Oceano::Seabird

A l’origine, cet outil permet de générer des extensions en XS à partir de fichiers d’entête C et il présente quelques défauts pour la génération de distributions. Il pose des contraintes sur la version courante de Perl, il génère des éléments inutiles et une arborescence imparfaite (ce qui a été corrigé dans les dernières versions).

Module::Starter

Une seconde solution consiste à utiliser le module Module::Starter. Ce module a été créé pour combler les lacunes de h2xs. Il est prévu pour créer des squelettes de distributions et permet de spécifier plusieurs modules. Il est aussi possible de préciser les noms et email de l’auteur. La documentation est mieux intégrée au code et des tests permettent de vérifier celle-ci. L’installation de ce module se fait comme n’importe quel module :

$ perl -MCPAN -e'install Module::Starter'

Son utilisation est la suivante :

$ module-starter --module=Oceano::Seawater,Oceano::Seabird --author="Prenom Nom" --email="prenom.nom@ird.fr"

L’arborescence générée par la commande module-starter est la suivante :

Oceano-Seawater/
 Changes           changements de chaques versions
 lib/              repertoire contenant les modules
   Oceano/
     Seabird.pm
     Seawater.pm
 Makefile.PL       script d'installation
 MANIFEST          liste des fichiers de la distribution
 README            informations pour l'utilisateur
 t/                repertoire contenant les tests
   00-load.t
   boilerplate.t
   pod-coverage.t
   pod.t

A partir de ce squelette, pour chaque version du module, il faut mettre à jour :
- les modules évidemment, dans le repertoire lib
- les fichiers de test dans le repertoire t
- le fichier MANIFEST s’il y a des nouveaux fichiers dans la distribution
- le fichier Changes avec les ajouts et les modifications effectués
- le fichier README s’il y a des informations spéciales à donner à l’utilisateur
- le numéro de version du module ($VERSION)
- la documentation POD en fonctions des changements dans le code

Il faut savoir qu’il existe une alternative à Module::Starter qui est ExtUtils::ModuleMaker. Ces deux modules sont conseillés par le CPAN pour créer des distributions.

Tester ses modules

Module::Starter génère automatiquement les fichiers de test suivants :

00.load.t       chargement des modules
pod.t           documentation POD bien formée
pod-coverage.t  documentation couvre les fonctions

Il est fortement recommandé de créer d’autres fichiers .t pour tester au maximum son code.
Si on utilise le module Test::More pour faire nos tests, ce qui est conseillé, il faut lui indiquer le nombre de tests que l’on compte effectuer. Ainsi dans notre fichier de test on aura la ligne suivante :

use Test::More tests => 2;

Ensuite il suffit d’utiliser les fonctions de ce module. Ces fonctions retournent "ok" ou "not ok" selon l’issue du test et son interprétées par Test::Harness :

ok($obtenu == $prevu);
ok($obtenu eq $prevu);

Vérifie que l’expression est vraie.

is($obtenu, $prevu);
isnt($obtenu, $prevu);

Vérifie que les deux paramètres sont égaux. Apporte plus d’informations que ok().

like($obtenu, qr/prevu/);
unike($obtenu, qr/prevu/);

Vérifie que $obtenu correspond à l’expression régulière.

use_ok($module);
require_ok($module);

Vérifie que le module a bien été chargé. Il est conseillé de mettre ces fonctions dans un bloc BEGIN{}.

diag($message);

Affiche un message de diagnostic de manière plus sûre que print STDERR.

SKIP: {
 skip $raison, $nombre if $condition;
 ...
}

Permet de sauter des tests, par exemple si un module n’existe pas sur le système. Il faut indiquer la raison, le nombre de tests, et la condition.

Pour faciliter le débogage, il est possible d’ajouter un argument aux fonctions de test pour indiquer un nom pour le test :

ok($obtenu eq $prevu, $nom_du_test);

Il existe d’autres fonctions de test qui sont décrites dans la documentation du module.

Pour tester et créer la distribution, il suffit de taper les commandes suivantes :

$ perl Makefile.PL
$ make
$ make test
$ make dist

On obtient une archive prête à être diffusée. Pour voir le détail des tests taper :

$ make test TEST_VERBOSE=1

Reconnaître du texte à l’aide d’expressions régulières

Les expressions régulières sont un élément important de la programmation aussi bien en Perl que dans d’autres langages (sed, awk, vi, java, Matlab, Python, etc). Elles permettent de décrire et reconnaitre et manipuler du texte à partir de "motifs".

if( $reponse =~ m/regex/ ) { block d'instructions };

Devient : Si le texte dans la variable réponse est reconnu par regex, alors ... on exécute le block d’instructions

On peut également utiliser la construction suivante pour affecter la variable $ship à partir de la ligne courante $_ lors du parcourt d’un fichier contenant la ligne :

Ship : CORAL

ou

Navire : Fort de France

 if( /Ship:\s+(\.*)/)        {
   ($ship) = /Ship:\s+(\w+)/;
 }
ou
 if( /Navire\s*:\s*(\.*)/)        {
   ($ship) = $1;
   chop $ship;  # enlève le dernier caractère
 }

autre exemple, extraire la date et l’heure dans un fichier, puis la formater avec le module Date::Manip :

 if( m[Date\s*:\s*(\d+)/(\d+)/(\d+)]) {
     ($jour,$mois,$annee) = ($1, $2, $3);       
   };       
 if( /Heure\s*:\s*(\d+)[:hH](\d+)/ ) {  
     ($heure,$min)  = ($1, $2);       
   };
 &Date_Init( "TZ=UTC" );
 $date = &ParseDate( $date );
 $date = &UnixDate($date,"%H:%M %d/%m/%Y");

Pour faciliter la mise au point des motifs, on pourra utiliser les logiciels Regex Coach ou Expresso.

Instruction switch

Il n’y a pas d’instruction switch officielle en Perl, car il existe déjà plusieurs façons d’écrire l’équivalent. Vous pourriez écrire à la place de ce qui précède :

   SWITCH: {
       $abc = 1, last SWITCH  if /^abc/;
       $def = 1, last SWITCH  if /^def/;
       $xyz = 1, last SWITCH  if /^xyz/;
       $nothing = 1;
   }

La construction de BLOC est particulièrement élégante pour créer des structures case :

   SWITCH: {
       if (/^abc/) { $abc = 1; last SWITCH; }
       if (/^def/) { $def = 1; last SWITCH; }
       if (/^xyz/) { $xyz = 1; last SWITCH; }
       $nothing = 1;
   }

Une alternative consiste à utiliser le module Switch
présent dans les versions récentes (eg 5.8). Il semblerait qu’une implémentation sera disponible à partir de la version 6.0 qui utiliserait les mots clés ’given’ et ’when’ à la place des traditionnels ’switch’ et ’case.

Ecrire un programme perl en une ligne

Avant Perl, il était d’usage d’utiliser des programmes scpécifiques tel que sed, awk, grep, find, etc... associés au scripts et autres commandes en shell, le tout enchainé par les tubes (pipes).

Quoique dans l’ensemble extremement efficace, ces outils restent l’apanache des administrateurs systèmes rompus à leurs usages et souvent difficiles à maitriser/mémoriser pour le néophyte.

En général, un uniligne Perl remplacera avantageusement cet ensemble de "pipes" et autres commandes.

Pour inclure du code uniligne, il suffit d’utiliser le paramètre -e

Quelques exemples :

Hello word :

perl -e 'print "Hello, world\n";'

Remplacer la chaine toto par titi dans un fichier :

perl -i -pe 's/\btoto/\titi/g' <file>

Remplacer la chaine DEPTH par DEPH dans les fichiers du repertoire courant et faire une copie de sauvegarde :

perl -i.bak -pe 's/\bDEPTH/\DEPH/g' *

Pour plus d’exemples et d’informations suivre les liens.

Ressources utiles

- En Français

- En Anglais

En général, une simple requête sur Google suffira pour trouver votre bonheur car la documentation sur internet est importante.

Le site officiel de Perl