Dernière version sur https://formation-perl.fr/guide-perl.html
© 2002-2024 Sylvain Lhullier - Permission est accordée de copier et distribuer ce document sans modification
et à condition de fournir un lien vers la page https://formation-perl.fr/guide-perl.html
Envie d'une formation Perl ?
Sylvain Lhullier propose des formations au langage Perl,
contactez-le.
Pour le moment nous avons écrit des programmes dont les interactions avec leur environnement étaient faibles. Nous allons voir dans cette partie comment manipuler des fichiers en Perl. Les fichiers se retrouvent dans tous les langages, mais la manière très simple et très puissante de les manipuler fait des fichiers une facilité de Perl.
Perl dispose d'opérateurs prenant en paramètre un nom de fichier ;
ce nom de fichier doit être un scalaire (une variable ou une constante).
Leur valeur de retour est souvent booléenne et quelquefois numérique.
Les coutumiers du shell retrouveront de nombreuses options de la commande
test
.
-e
teste si son paramètre est un chemin valable
dans le système de fichiers (répertoire, fichier, etc.).
On pourrait l'utiliser ainsi :
if( -e "/usr/tmp/fichier" ) { print "Le fichier existe\n"; }
-l
teste si son paramètre est un lien symbolique.
Ceci n'exclut pas que -f
ou -d
renvoie vrai.
-r
teste si le programme a le droit de lire
le fichier/répertoire/etc passé en paramètre.
-x
teste si le programme a le droit d'exécuter
le fichier ou d'accéder (ou axéder :-)
) au répertoire.
-o
teste si le fichier appartient à l'utilisateur
qui exécute le programme.
-s
teste si le fichier est non vide ; en fait
cet opérateur renvoie la taille du fichier.
-M
renvoie l'âge en jour du fichier (depuis le
début de l'exécution du programme).
Il existe tout plein d'autres opérateurs sur les fichiers ;
pour en connaître la liste complète, je vous invite à lancer la commande
perldoc -f -X
Voici quelques exemples d'utilisation de ces opérateurs :
my $file = "/usr/doc/perl"; if( -f $file && -w $file ) { .... } my $taille = -s $file; my $age = -M $file;
Simple et efficace.
glob
La fonction glob
prend en argument une expression
et renvoie une liste de noms de fichiers. Cette liste correspond à l'évaluation
de l'expression selon les wildcards du shell.
Par exemple, glob( '*.o' )
renvoie la liste des fichiers du répertoire courant ayant l'extension
.o
Notez bien qu'il ne s'agit pas d'une expression régulière (pour ceux qui
connaissent ; pour les autres, nous en parlerons plus tard), mais bien
d'une expression telle qu'on la donnerait à un shell :
ls [A-Z]*.h
liste tous les fichiers commençant
par une majuscule ayant l'extension .h
Il existe une syntaxe plus concise et au comportement identique à cette fonction : l'expression peut être mise entre chevrons. Les deux lignes suivantes effectuent la même opération :
@l = glob('/usr/include/*.h'); @l = </usr/include/*.h>;
Après l'exécution d'une de ces deux lignes, le tableau @l
contient la liste des noms absolus des fichiers d'include pour le C
du répertoire /usr/include
Voici un premier exemple de manipulation de noms de fichiers :
#!/usr/bin/perl use strict; use warnings; foreach my $name ( glob('*') ) { print "$name\n" if( -l $name ); }
Il affiche les liens symboliques du répertoire courant.
Voici un second exemple :
#!/usr/bin/perl use strict; use warnings; foreach my $name ( glob('.* *') ) { next if( ! -d $name ); next if( ! -w $name ); print "$name : ". ( -s $name ) ."\n"; }
Ce programme affiche le nom et la taille des sous-répertoires
du répertoire courant sur lesquels j'ai les droits d'écriture
(y compris ceux commençant par un point, donc .
et ..
).
Pour lire ou écrire dans un fichier, il est nécessaire de l'ouvrir
préalablement. La fonction effectuant cette opération en Perl se
nomme open
et sa syntaxe est la suivante :
open(
descripteur,
mode,
nom-de-fichier )
Le paramètre descripteur sera l'identifiant du fichier
après ouverture (on pourrait parler de descripteur de fichier).
C'est ce descripteur qui devra être fourni aux fonctions de lecture et d'écriture
pour manipuler le fichier.
Il s'agit d'une variable que vous devez déclarer, par exemple directement dans le open
.
Le paramètre mode est un scalaire (chaîne de caractères) comportant un ou deux caractères indiquant le mode d'ouverture :
Tableau 2.
Caractère(s) | Mode d'ouverture |
---|---|
< | lecture |
> | écriture (écrasement) |
>> | écriture (ajout) |
+> | lecture et écriture (écrasement) |
+< | lecture et écriture (ajout) |
Les habitués du shell retrouveront certaines notations connues.
Par exemple open(my $fd1,'<','index.html')
ouvre le fichier
index.html
en lecture et open(my $fd2,'>','index.html')
l'ouvre en écriture-écrasement (c'est-à-dire que le fichier sera vidé
avant que le curseur ne soit placé au début du fichier).
Cette fonction open
renvoie une valeur booléenne
vrai ou faux indiquant le bon déroulement ou non de l'opération.
Il est très important de tester les valeurs de retour des fonctions
manipulant les fichiers (cela est vrai, quel que soit le langage),
car on ne peut jamais être sûr de rien. Voici deux exemples de tests
de la valeur de retour d'open
:
if( ! open($fd,'>>','data.txt') ) { exit(1); }
Dans ce premier exemple, on tente d'ouvrir en ajout un fichier
data.txt
; en cas d'impossibilité,
on appelle la fonction exit
qui met fin au programme
(la valeur 1 signale une erreur ; la valeur 0 signalant la fin
normale du programme, les autres valeurs sont utilisées pour signaler
au shell appelant une erreur). Vous noterez que l'utilisateur qui
exécute le programme n'est pas informé de la cause de l'échec ;
le programme se termine, tout au plus sait-il qu'il y a eu un problème
avec l'ouverture de ce fichier, mais il n'en connaît pas la cause.
L'exemple suivant va nous permettre de lui afficher un joli message
d'erreur :
open($fd2,'<','/tmp/$a') or die("open: $!");
Nous cherchons ici à ouvrir en lecture le fichier dont le nom serait
la concaténation de la chaîne /tmp/
et du
contenu de la variable $a
.
La fonction die
met fin au programme comme
exit
le ferait, mais affiche en plus le paramètre
qu'on lui passe. En l'occurrence, le paramètre fourni est la chaîne
de caractères comportant le nom de la fonction qui cause l'échec
(on aurait pu ajouter le nom du fichier) ainsi que la variable
$!
. En contexte de chaîne de caractères, cette
variable magique $!
contient le message errno de la dernière
erreur survenue, par exemple No such file or directory
ou Permission denied
, etc. L'utilisateur
est donc informé de la cause de la fin du programme.
La syntaxe open() or die();
ainsi que sa signification
proviennent de l'évaluation paresseuse du or
.
En effet, dans l'expression
(a or
b)
si a est vrai, il n'est pas nécessaire d'évaluer
b pour connaître la valeur de l'expression.
C'est ce qu'il se passe ici : si open()
renvoie vrai, il n'est pas nécessaire d'évaluer die()
.
Les descripteurs de fichier sont d'une espèce étrange en Perl,
le débutant s'abstiendra de chercher à trop comprendre les mécanismes
sous-jacents. Ce que l'on pourrait dire, c'est qu'il n'est pas
nécessaire de déclarer un descripteur de fichier, la fonction
open
valant déclaration.
Une fois un fichier ouvert, il nous est possible d'écrire et/ou de lire dedans (selon le mode d'ouverture) et de le fermer.
La lecture des fichiers texte s'effectue typiquement au moyen de l'opérateur chevrons, cette lecture se faisant ligne par ligne.
$l = <$fd>;
Cette instruction lit la prochaine ligne disponible du fichier FIC. Vous noterez bien que l'opérateur chevrons (diamond operator en anglais) est ici en contexte scalaire. En contexte de liste, il renvoie la liste de toutes les lignes restant dans le fichier :
@t = <$fd>;
Cette instruction « absorbe » toutes les lignes du fichier dans une
liste qui est placée dans le tableau @t
.
Pour itérer sur les lignes d'un fichier, il est courant de faire ainsi :
while( defined( $l = <$fd> ) ) { chomp $l; print "$. : $l\n"; }
La boucle while
donne pour valeur à la variable
$l
une à une toutes les lignes du fichier.
La fonction chomp
supprime le dernier caractère
s'il s'agit d'un retour à la ligne.
La variable spéciale $.
vaut le numéro de la
ligne courante du dernier fichier lu (ici $fd
).
Si vous utilisez la variable spéciale omniprésente $_
,
la construction
while( defined( $_ = <$fd> ) )
peut même s'abréger en :
while( <$fd> )
Pour écrire dans un fichier, nous allons utiliser les fonctions
print
et printf
que nous avons déjà vues. Elles prennent en premier argument
le descripteur de fichier :
print( $fd "toto\n" ); printf( $fd "%03d", $i );
Il faut noter qu'il n'y a pas de virgule après le descripteur
de fichier (il ne faut pas en mettre !). Les parenthèses sont comme toujours
optionnelles autour des arguments, mais permettent de lever certaines
ambiguïtés. La fonction printf
fonctionne comme
printf
ou fprintf
du C
et ne sera donc pas détaillée ici
(voir man 3 printf
).
Pour fermer un descripteur de fichier (et donc vider les buffers
associés), il faut faire appel à la fonction close
:
close( $fd );
À noter que si vous réutilisez un descripteur de fichier dans un
open
sans faire de close
au préalable, Perl ne rouspétera pas et fermera consciencieusement
le premier fichier avant d'ouvrir le deuxième.
Il existe plusieurs fichiers ouverts automatiquement par Perl dès le lancement du programme :
STDOUT
: la sortie standard
(souvent le terminal). Par défaut print
et
printf
écrivent sur ce flux ;
STDERR
: la sortie d'erreur standard
(souvent le terminal). Par défaut warn
et die
écrivent sur ce flux ;
ARGV
: ce descripteur est un peu
spécial, mais souvent bien pratique. Les lignes lues sont celles
des fichiers de la ligne de commande (donc les arguments passés
au programme sont considérés comme des noms de fichier) ;
si le programme est lancé sans argument, l'entrée standard est lue.
N.B. Vous pouvez écrire soit <ARGV>
soit
<>
La variable spéciale $ARGV
contient le nom du fichier en cours de lecture.
Discutons un peu de la manipulation de fichiers binaires.
Les exemples de lecture de fichiers donnés jusqu'ici ne conviennent
pas à de tels fichiers, mais plutôt à des fichiers contenant du texte.
Vous pouvez, pour cela, utiliser la fonction
getc
qui renvoie le prochain caractère disponible :
$c = getc($fd);
. Vous pouvez aussi faire usage
de la fonction read
qui lit un nombre déterminé
de caractères :
$tailleLue = read( $fd, $tampon, $tailleÀLire );
.
Les données seront placées dans la variable $tampon
.
À la fin du fichier, ou s'il y a un problème, le tampon n'est
pas complètement rempli. C'est pour cela que l'on récupère la
valeur de retour de read
.
Pour écrire des données non textuelles dans un fichier, vous pouvez
tout à fait utiliser les fonctions print
et
printf
, car les chaînes de caractères de Perl
peuvent contenir le caractère de code ASCII zéro. On notera que la
fonction write
existe, mais n'est pas l'inverse
de read
.
S'il vous est nécessaire d'utiliser les fonctions d'entrée/sortie
bas niveau, voici leurs noms en Perl : sysopen
,
sysread
, syswrite
et
close
.
Voici le prolongement de l'exemple donné pour les tables de hachage. Nous n'allons plus considérer que les mots sont contenus dans un tableau, mais nous allons les extraire d'un fichier.
#!/usr/bin/perl use strict; use warnings; open(my $fd,"<$filename.txt") or die"open: $!"; my($line,@words,$word,%total); while( defined( $line = <$fd> ) ) { @words = split( /\W+/, $line ); foreach $word (@words) { $word =~ tr/A-Z/a-z/; $total{$word}++; } } close($fd); foreach $word (sort keys %total) { print "$word a été rencontré $total{$word} fois.\n"; }
On effectue une boucle while
sur les lignes
du fichier. Chaque ligne est alors découpée en mots par la fonction
split
(\W+
correspond
aux suites de caractères non alphanumériques, nous verrons cela
dans la suite lorsque nous étudierons les expressions régulières).
Chaque mot est mis en minuscules au moyen de l'opérateur
tr
(que nous expliquerons avec les expressions
régulières).
open
Il est facile en Perl de lancer une commande shell et de récupérer sa sortie standard ou de fournir son entrée standard.
Pour lire la sortie standard d'un programme, il suffit d'utiliser la syntaxe suivante :
open(HANDLE,"
commande|")
par exemple :
open(my $fd1,"ls|") open(my $fd2,"df -HT $device|")
Les lignes lues via le descripteur de fichier ainsi créé seront celles que la commande aurait affichées à l'écran si on l'avait lancée depuis un terminal.
La syntaxe
open(HANDLE,"|
commande")
permet de lancer une commande. Les lignes écrites dans le descripteur de
fichier constitueront son entrée standard, par exemple :
open(my $fd3,"|gzip > $a.gz") open(my $fd4,"|mail robert\@bidochon.org")
Quoi de plus simple ?