open(FILE, "< myfile") || die "Can't open 'myfile'\n"; while (<FILE>) { ... }Cependant, vous n'avez peut-être pas saisi tout ce qui se cache derrière ces chevrons. Ils ne concernent pas uniquement les file handles.
ARGV
. Quand il est
utilisé à l'intérieur d'une boucle de ce type :
while (<ARGV>) { ... }Chaque élément de la liste des arguments,
@ARGV
,
est traité en tant que nom de fichier. Perl va essayer d'ouvrir chacun
d'eux, d'en lire le contenu, puis de passer au suivant. Vous aurez un message
d'erreur si l'un deux ne peut pas être ouvert, mais la boucle continuera
jusqu'à épuisement du contenu de la liste. Si le programme a
été exécuté sans argument, (i.e., si
@ARGV
est vide), alors la boucle précédente lira ses
informations sur le standard input comme doit le faire tout bon programe
UNIX. Au passage, puisque la construction
est si courante,
on peut écrire plus brièvement <>
, ce qui a la
même signification.
while (<>) { ... }
Le scalaire $ARGV
est associé au file handle
ARGV
. Il contient le nom du fichier courant ouvert. Nous
pouvons utiliser ceci pour écrire un programme
grep
simpliste:
$pat = shift @ARGV; $many = @ARGV > 1; while (<>) { next unless /$pat/; print "$ARGV:" if $many; print; }Le programme utilise
shift()
pour extraire le premier
argument de la liste, le motif de la recherche. Tous les autres
arguments sont traités comme des noms de fichier. Si plusieurs noms
de fichiers sont passés en argument alors le nom du fichier courant
est imprimé avant l'ensemble des lignes contenant le motif
(exactement comme le fait le programe UNIX grep
).
Le seul grain de sable avec cette technique de ARGV
est que
lorsque chaque fichier est ouvert, la variable spéciale $.
qui
contient le numéro de ligne courant n'est pas remise à zéro. Si cela vous pose un
problème, utilisez l'astuce suivante :
$oldname = ''; while (<>) { if ($ARGV ne $oldname) { $lineno = 0; $oldname = $ARGV; } $lineno++; ... }et utilisez
$lineno
en lieu et place de $.
. Vous vous
demandez peut-être pourquoi tout ce fatras avec $lineno
plutôt que de simplement assigner $.
. Tous simplement par ce
que cela ne marche pas : $.
ne peut être remise à
zéro qu'à l'appel de close()
.
<$file>
, est une
indirection dans le file handle. Perl essayera de lire ses données dans
le fichier dont le nom est la chaîne de caractère contenue dans la
variable <$file>
. Par exemple :
open(FILE, "/etc/motd") || die "Can't open /etc/motd\n"; $file = 'FILE'; $line1 = <FILE>; $line2 = <$file>;En quoi cela est-il utile ? Premièrement ceci permet de passer élégamment des noms de fichier à des routines :
open(FILE, "/etc/motd") || die "Can't open /etc/motd\n"; &mysub(FILE); sub mysub { local($file) = @_; while (<$file>) { ... } }Deuxièmement, la chaîne contenue dans la variable n'a pas besoin d'être un identificateur valide. Elle peut même être, par exemple, le nom du fichier à ouvrir :
for (0..8) { $file = "/var/adm/messages.$_"; open($file, "$file") || die "Can't open $file\n"; }ainsi nous pourrons faire des choses du genre :
&do_something_with ("/var/adm/messages.0"); sub do_something_with { local($file) = @_; while (<$file>) { ... } }Ceci peut accroître considérablement la lisibilité de vos programme en particulier si vous avez de nombreux fichiers ouverts. Troisièmement, nous pouvons construire des listes ou des tableaux de références à des file handles.
@myfiles = 0..7; for (@myfiles) { open($myfiles[$_], "syslog.$_") || die "Can't open syslog.$_\n"; }Notez que bien que nous avons pu utiliser une référence à un élément d'un tableau dans la fonction
open
de l'exemple
précédant, nous ne pouvons utiliser qu'un scalaire à
l'intérieur des chevrons. Nous devons donc déréférencer la variable
@myfiles
avant de l'utiliser:
$file = $myfiles[3]; $line = <$file>; print "$line";
while (<*.c>) { print "Checking out $_...\n"; system("co -l $_"); }ou vous pouvez insérer tous les noms dans une liste :
chmod 0644, <*.c>;Cependant ne concluez pas faussement des deux exemples précédants que les métas caractères se comportent comme un file handle. Cet autre exemple
$file1 = <*.c>; print "$file1\n"; $file2 = <*.c>; print "$file2\n";imprime deux fois le même nom de fichier (et fork un sous-shell deux fois également), au lieu d'imprimer le premier puis du second des noms correspondant à l'expansion. Prenez-y bien garde si vous ne voulez pas assister à des catastrophes.
L'interprétation des variables a lieu avant l'expansion des métas
caractères, mais vous ne pouvez pas écrire <$glob>
parce que c'est un file handle indirect. Il faut placer des accolades autour
du nom de votre variable pour forcer son interpolation.
$glob = "*.c"; @c_files = <${glob}>;Pour ceux qui n'y auraient pas pris garde, nous venons juste de mettre en relief un des aspects sournois de Perl : une situation où
$glob
et ${glob}
n'ont pas la même
signification.
Comme Perl exécute un exec()
pour forcer l'expansion
dans un shell plutôt que d'employer une fonction d'expansion interne,
il est plus efficace (en terme de vitesse d'exécution, mais
peut-être pas en terme de lisibilité ou de taille du code)
d'utiliser la fonction interne de parcours de répertoires:
opendir(DIR, ".") || die "Can't open directory `.'\n"; @c_files = grep(/\.c$/, readdir(DIR)); closedir(DIR);Notez que l'expansion retourne toujours les noms dans leur ordre alphabétique alors que le code ci-dessus ne le fait pas (vous pouvez toujours utiliser
sort()
pour trier la liste dans la
méthode ci-dessus).
<>
est utile est devrait faire partie du
bagage tout programmeur Perl. Les file handles indirects et les métas
caractères sont moins fréquemment utilisés mais peuvent
souvent améliorer la clarté et la lisibilité du code. Les
file handles indirects en particulier peuvent être utilisés pour
éviter d'Traduction de ;login: Vol. 18 No. 5, October 1993.
Dernière édition: 15 mars 1998 phb Original 05/24/96ah |
|