Perl a été créé par Larry Wall au milieu des années 80 parce que awk montrait ses limites dans le travail qu’il voulait effectuer.
L’orthographe Perl (avec une majuscule) est le plus souvent employée pour parler du langage tandis que perl (en minuscules) fera référence à l’interpréteur.
L’orthographe PERL (comme s’il s’agissait d’un acronyme) est incorrecte.
L’interpréteur Perl compile et exécute le programme en une seule étape. C’est pourquoi les messages d’erreur comportent souvent :
Execution of programme aborted due to compilation errors.
Perl a longtemps été le langage couteau suisse des adminSys.
Si Python lui fait de plus en plus concurrence sur ce créneau, il reste encore très utilisé et il n’est pas rare d’avoir besoin d’adapter un script Perl provenant d’un précédent adminSys.
Il peut tout aussi bien servir à faire des scripts quick and dirty à jeter après utilisation, que des applications complexes grâce aux très nombreux modules Perl présents sur le CPAN (http://metacpan.org/).
#!/usr/bin/perl
use warnings;
use strict;
Les lignes autres que le shebang (#!/usr/bin/perl
), sont appelées des pragmas. Ce sont des indications données au compilateur, lui précisant quelque chose à propos du code.
use warnings
permet d’obtenir des avertissements de la part de perl lorsqu’il rencontre des éléments suspects dans le programme. Ces avertissements ne modifient pas le déroulement du programme mis à part quelques plaintes de temps en temps.
Perl est un langage extrêmement permissif mais l’emploi du pragma use strict
permet de s’imposer une certaine discipline (déclaration préalable des variables entre autres), ce qui permet souvent d’avoir un code plus compréhensible et plus efficace.
Dans les extraits de code présenté ici, les deux pragmas sont positionnés.
En Perl, les variables ne sont pas typées.
Il y a basiquement trois structures de données en Perl : - les variables scalaires1 ; - les tableaux ; - les tables de hashage.
Par défaut, en Perl, toutes les variables sont globales, il est donc possible d’y accéder depuis tout endroit du programme. On peut créer des variables locales en les déclarant avec my
.
Cependant, l’usage du pragma strict
nous force à déclarer toutes les variables avec my
. Une variable ne sera donc globale que si on prend le soin de la déclarer en dehors de toute boucle ou sous-programme.
Exemple de déclarations de variables scalaires :
my $var = "string";
my $var2 = 42;
my $var3;
Une fois la variable déclarée avec my
, il n’est plus nécessaire d’utiliser my
(cela créerait même un avertissement lors de l’exécution du programme) :
my $foo = "bar";
$foo = "baz";
Le $
devant le nom de la variable est appelé un sigil. Il existe d’autres sigils en Perl : @
pour les tableaux, et %
pour les tables de hachage.
On peut donner des valeurs à un tableau de deux manières différentes : soit en passant les paramètres séparés par des virgules (et en mettant les chaînes de caractères entre guillemets), soit en utilisant qw
qui permet de s’affranchir des guillemets et des virgules. Par contre si une chaîne contient une espace, il faudra remettre les guillemets.
my @tab = ("valeur", 42, "autre", "blip blop");
my @tab2 = qw(valeur 42 autre "blip blop");
NB : en informatique, les éléments d’un tableau sont comptés à partir de 0. Les éléments d’un tableau de N éléments sont donc numérotés de 0 à N - 1.
Le sigil du tableau passe de @
à $
lorsqu’on accède à un de ses éléments.
# Attention : c’est bien un $ pour accéder à l’élément du tableau
print $tab[0];
# On modifie ici la valeur du 1er élément du tableau
$tab[0] = 42;
# Affichage du contenu : "4242autreblip blop"
print @tab;
# Affichage du contenu, mais séparé par des espaces : "42 42 autre blip blop"
print "@tab";
# Affiche le nombre d’éléments du tableau : 4
print scalar(@tab);
# Réinitialisons le tableau
@tab = ("valeur", 42, "autre", "blip blop");
On voit ici que @tab ne renvoit pas forcément la même chose selon le contexte dans lequel on l’utilise. On parle ici de contexte de liste et contexte de scalaire2.
Perl choisira automatiquement la valeur nécessaire selon le contexte dans lequel la variable est utilisée :
# Contexte de scalaire :
# 42 + 4 = 46
$nombre = 42 + @tab;
# Contexte de liste :
# on recopie (42, 42, "autre", "blip blop") dans @copie_tab
@copie_tab = @tab;
pop
, push
, shift
et unshift
Les deux premiers permettent de manipuler aisément les tableaux par leur fin :
pop
renvoie la valeur du dernier élément du tableau et supprime ce dernier élément
# $last vaut "blip blop" et @tab vaut ("valeur", 42, "autre")
$last = pop(@tab);
# On se contente de supprimer le dernier élément
pop(@tab);
push
ajoute au contraire des éléments au tableau.
# @tab vaut ("valeur", 42, "autre", nouveau")
push(@tab, "nouveau");
Les deux derniers manipulent les tableaux par leur début :
shift
renvoie la valeur du premier élément du tableau et supprime ce premier élément
@tab = qw(valeur 42 autre);
# $first vaut "valeur" et @tab vaut (42 "autre")
$first = shift(@tab);
# On se contente de supprimer le premier élément
shift(@tab);
unshift
ajoute au contraire des éléments au tableau.
# @tab vaut ("nouveau", 42 "autre")
unshift(@tab, "nouveau");
Une table de hachage est une structure de données comme un tableau, en cela qu’elle peut contenir un nombre quelconque de valeurs et les retrouver à la demande. Cependant, au lieu de repérer les valeurs par un indice numérique, comme avec les tableaux, elles sont repérées par un nom.
my %hash = (
"cle1" => "valeur",
"cle2" => 42,
"cle3" => "autre",
);
Il existe d’autres manières d’affecter des valeurs à une table de hachage mais celle-ci a l’avantage d’être la plus lisible.
print $hash{"cle1"}; # Affiche "valeur"
$hash{"cle1"} = 42; # Affectation
@tab_cles = keys %hash; # @tab_cles vaut "cle1 cle2 cle3"
@tab_valeurs = values %hash; # @tab_valeurs vaut "42 42 autre"
Les structures if, if else, if elsif, while, do while fonctionnent comme dans la plupart des langages de programmation.
Mais comme Perl, c’est trop la classe, on peut faire des raccourcis marrants qui font gagner du temps.
for
et foreach
foreach
est en fait un synonyme de for
, vous pouvez utiliser indifféramment l’une ou l’autre.
Vous pouvez les utiliser pour faire une boucle à la manière du langage C
:
for (my $i = 0; $i <= 42; $i++) {
# Attention : print n’effectue pas de retour a la ligne
# On va donc utiliser \n
print "$i\n";
}
Ou vous pouvez l’utiliser d’autres manières
# Tableau particulier (suite de nombres)
# Pour $i de 0 à 42, inclus
foreach my $i (0..42) {
# Affichage identique que celui de la boucle for vue ci-avant
print "$i\n";
}
# Tableau
foreach my $element (@tab) {
print "$element\n";
}
# Tables de hachage (tableaux associatifs)
for my $cle (keys(%hash)) {
print "$hash{$cle}\n"; # Affiche chaque valeur de la table de hachage
}
Le second exemple démontre qu’il est aussi possible de remplir un tableau avec les nombres de n
à m
de façon automatisée :
my @tab = (42..1337);
Mais cela fonctionne aussi avec les lettres !
my @tab = (a..z);
if
et unless
Perl possède la structure de contrôle unless
, qui est le contraire de if
.
Affichons quelque chose si la variable $a
n’est pas égale à 42 :
if ($a != 42) {
print "quelque chose\n";
}
Cette syntaxe est équivalente à :
unless ($a == 42) {
print "quelque chose\n";
}
L’utilisation de l’une ou l’autre des structures est au libre choix du programmeur mais il est conseillé de les choisir en fonction de la lisibilité que cela apportera au code.
Il est possible d’utiliser if
et unless
d’une autre manière :
print "quelque chose\n" if ($a != 42);
print "quelque chose\n" unless ($a == 42);
Vous remarquerez que cette syntaxe est relativement proche du langage naturel, améliorant de fait sa lisibilité. Cependant, on ne peut l’utiliser que dans le cas où il n’y pas d’action si la condition n’est pas remplie et où il n’y a qu’une seule action à exécuter.
Celles-ci sont appelées sous-routines dans la terminologie Perl.
On les déclare avec le mot-clé sub
qui, contrairement à my
qui n’est obligatoire que si on utilise le pragma strict
, doit toujours être utilisé.
sub division {
# Premier argument divise par le second
return $_[0] / $_[1];
}
Il est aussi possible de définir une ligne permettant de donner aux arguments des noms plus explicites :
sub division {
my ($nombre, $diviseur) = @_;
return $nombre / $diviseur;
}
Vous aurez remarqué que contrairement à bon nombre d’autres langages, Perl n’utilise pas ce qu’appelle les signatures pour ses fonctions : pas de sub foo(bar) {}
qui assigne automatiquement les arguments passés à la fonction. Il est possible de les utiliser dans les dernières version de Perl, mais s’agissant d’une fonctionnalité récente, vous ne les rencontrerez que rarement (du moins pour l’instant).
Les arguments passés à une fonction constituent le tableau @_
. On peut utiliser ses éléments de façon classique ($_[0]
) ou, pour plus de lisibilité, affecter ses éléments à des variables nommées de façon plus explicite.
La syntaxe my ($a, $b) = @_;
affecte à $a
et $b
les valeurs des deux premiers éléments de @_
, sans se soucier de connaître le nombre d’éléments de @_
: si @_
contient plus de deux éléments, les éléments surnuméraires seront ignorés, s’il en a moins, $b
(et $a
aussi si @_
a une taille nulle) aura pour valeur undef
.
On utilise l’esperluette &
pour indiquer qu’il s’agit d’une fonction (on peut cependant s’en passer dans certaines circonstances).
print &division(42, 10); # Affiche 4.2
Perl est particulièrement réputé pour sa force sur le traitement des expressions régulières.
Pour la syntaxe des expressions régulières, vous pouvez aller sur http://sylvain.lhullier.org/publications/intro_perl/chapitre10.html (vous y trouverez aussi des exercices).
L’expression régulière recherchée est appelée motif. On place le motif entre slashes3 et on utilise =~
pour indiquer dans quelle variable on doit rechercher le motif. La recherche de motif renverra true
ou false
dans un contexte de scalaire.
if ($foo =~ /bar/) {
print "\"bar\" a ete trouve dans \$foo";
}
# Complètement équivalent
if ($foo =~ #bar#) {
print '"bar" a ete trouve dans $foo';
}
Vous noterez que les "
et $foo
n’ont pas été échappés dans le dernier exemple. En effet, la chaîne de caractère a été délimité par des apostrophes et non par des guillemets. Donc les guillemets n’ont pas à être échappés et $foo
ne sera pas interprété.
if($foo =~ /bar/i) {
print "\"bar\", \"bAr\" ou \"BAR\" a été trouvé dans \$foo";
}
Le i
collé à l’arrière du motif permet de faire une recherche insensible a la casse.
my $foobar = "foobarbar";
$foobar =~ s/bar/foo/;
# Affiche : foofoobar
print $foobar;
$foobar = "foobarbar";
# le g permet de ne pas limiter la substitution a la premiere occurence
$foobar =~ s/bar/foo/g;
# Affiche : foofoofoo (comme le collège)
print $foobar;
On peut également cumuler les options g
et i
en gi
. Il en existe d’autres (pour plus amples informations, RTFM4).
Sachez aussi qu’un certain nombre de caractères doivent être échappés par un anti-slash (ex : /5 . ? * etc.).
Les raccourcis suivants peuvent être utiles6 :
\d
: Représente tous les chiffres (équivalent à [:digit:]
ou [0-9]
)
\w
: Représente tous les caractères alphanumériques plus l’underscore, sans les accents (équivalent à [a-zA-Z0-9_]
)
\s
: Représente tous les caractères d’espacement (espace, passage à la ligne, tabulation, saut de page, retour chariot : équivalent à [ \n\t\f\r]
)
Allez, parce que Perl est trop puissant, on en remet une couche !
my $url = "http://www.cpan.org/foobar/";
my ($site, $dossier) = $url =~ /http:\/\/www.(\w+).org/(\w+)\/;
ou, et c’est là qu’on voit l’intérêt d’utiliser un autre délimiteur que /
:
my ($site, $dossier) = $url =~ #http://www.(\w+).org/(\w+)#;
L’entrée standard, c’est le plus souvent le clavier mais ça peut aussi être un fichier (si vous faites $ ./mon_prog < mon_fichier
par exemple) ou la sortie d’un autre programme.
while(defined(my $foo = <STDIN>)) { print "$foo"; }
Cette syntaxe demande à l’utilisateur d’entrer du texte au clavier. Celui-ci peut cesser de fournir les entrées par Ctrl+D. $foo
contiendra à chaque fois ce qu’a tapé l’utilisateur avant de valider par Entrée. S’il s’agissait d’un fichier, $foo
contiendra les lignes du fichier, l’une après l’autre.
On utilise chomp
pour supprimer le retour à la ligne qui finalise chaque ligne de texte (quand l’utilisateur tape sur Entrée pour valider son entrée, ou le passage à la ligne dans le cas d’un fichier) :
my $foo = "toto\n";
print $foo; # Affiche toto suivi d’un retour à la ligne
chomp($foo);
print $foo; # Affiche toto sans retour à la ligne
Un descripteur de fichier est le nom, dans un programme Perl, d’une connexion d’entrée/sortie entre le processus Perl et le monde extérieur. STDIN
, vu plus haut, est un descripteur de fichier spécial.
my $fichier = "fichier.txt";
# Ouverture en lecture seule
open(my $fh, "<", $fichier)
or die("Impossible d’ouvrir le fichier $fichier : $!\n");
# Ouverture en ecriture (reinitialise le fichier)
open(my $fh, ">", $fichier)
or die( ... );
# Ouverture en ecriture (ajoute a la fin du fichier)
open(my $fh, ">>", $fichier)
or die( ... );
# Facultatif (se ferme automatiquement a la fin du programme)
close($fh);
Il est également possible d’ouvrir un fichier en lecture/écriture (+>
: écrasement, +<
: ajout).
C’est bien joli d’ouvrir un fichier, encore faut-il s’en servir.
# Affiche chaque ligne du fichier
while(defined(my $foo = <$fh>)) { print "$foo"; }
# Écrit $foo dans le fichier ouvert en écriture
print $fh $foo;
Par défaut, Perl se place dans le répertoire d’appel du script. Il cherchera donc, par exemple, les fichiers qu’on lui dit d’ouvrir dans ce répertoire.
chdir("/home/asrall");
L’opérateur glob
permet l’expansion de nom de fichier exactement comme dans le shell et donc d’explorer le répertoire :
# Remplit un tableau de tous les noms de fichiers
# du répertoire courant correspondant au motif
my @fichiersPerl = glob("*.pl");
Notez bien que la syntaxe de glob
n’a rien à voir avec les regex !
Rapidement, quelques fonctions que vous aurez sûrement l’occasion d’utiliser :
# Si une variable n’a pas été initialisée, elle vaut undef
if(defined $foo) {
print "La variable \$foo a été définie.\n";
} else {
print "\$foo retourne la valeur undef.\n";
}
if(-d $foo) { print "$foo est un répertoire.\n"; }
if(-e $foo) { print "Le fichier $foo existe.\n"; }
if(-f $foo) { print "$foo est un fichier régulier.\n"; }
# Ces fonctions qui se ressemblent sont les mêmes que
# la commande test de bash (man test pour toutes les voir)
# Décompose $foo dans le tableau @tab d’après le motif (ici une espace)
my @tab = split(/ /, $foo);
# Caste $foo en entier
my $numerique = int($foo);
# Retourne un nombre aléatoire entre 0 et $max
my $aleatoire = rand($max);
# Retourne $foo en majuscules
my $enMajuscules = uc($foo);
# Retourne $foo en minuscules
my $enMinuscules = lc($foo);
# Trie le tableau @foo selon l’ordre asciibétique (1, 10, 2, a, etc.)
@foo = sort(@foo);
# Trie le tableau selon l’ordre alphanumérique (1, 2, 10, a, etc.)
@foo = sort { $a <=> $b } @foo;
Perl permet d’économiser énormément de caractères, voici quelques raccourcis très utilisés dans la communauté Perl.
for (1..42) {
print "$_\n";
}
foreach (@tab) {
print;
}
En cas d’absence du nom de variable, $_
prend automatiquement le relais.
De plus, en cas d’absence de paramètre, certaines fonctions prennent $_
comme valeur par défaut (c’est le cas ici pour le print du foreach).
Attention ! L’utilisation de la variable magique n’est pas conseillée pour un programme destiné à être réutilisé !
Utilisez-la dans vos scripts jetables si vous le souhaitez, mais elle nuit à la lisibilité du programme et donc à ses éventuelles adaptations.
while (<>) {
print;
}
Selon le contexte, le diamant peut représenter deux choses différentes : si un fichier est passé en argument à l’appel du script7, le diamant le lira ligne à ligne, sinon l’utilisateur sera invité à taper au clavier.
Perl se passe de la plupart des parenthèses des fonctions. Ces trois lignes sont identiques :
chomp($_);
chomp $_;
chomp;
http://perl.developpez.com/cours/?page=SommaireTutoriels#TutorielsDebuter
Introduction à Perl de Randal L. Schwartz, Tom Phoenix et Brian D. Foy
O’Reilly 2006, ISBN : 2-84177-404-X
Les modules additionnels de Perl sont disponibles sur http://metacpan.org.
Une variable scalaire est le nom d’un emplacement ne contenant qu’une seule valeur, au contraire, par exemple, des tableaux ou des tables de hachage.↩
On l’a vu précédemment, le scalaire c’est une seule valeur, la liste c’est logiquement plusieurs valeurs.↩
On peut aussi utiliser d’autres caractères mais on utilise traditionnellement les slashes↩
Read The Fabulous Manual↩
Si le délimiteur de la regex est un /↩
C’est faux : ils ne peuvent pas être utiles, ils le sont !↩
Attention, cette fois ça peut être de la forme $ ./mon_prog < mon_fichier
comme tout à l’heure ou $ ./mon_prog mon_fichier
.↩