Ceci est plus une suggestion sur la façon NE PAS le faire. J'ai juste eu du mal à trouver un bogue dans une assez grosse application Perl. La plupart des modules avaient leurs propres fichiers de configuration. Pour lire les fichiers de configuration dans leur ensemble, j'ai trouvé cette seule ligne de Perl quelque part sur Internet:
# Bad! Don't do that!
my $content = do{local(@ARGV,$/)=$filename;<>};
Il réaffecte le séparateur de ligne comme expliqué précédemment. Mais il réaffecte également le STDIN.
Cela a eu au moins un effet secondaire qui m'a coûté des heures à trouver: il ne ferme pas correctement le descripteur de fichier implicite (car il n'appelle pas close
du tout).
Par exemple, en faisant cela:
use strict;
use warnings;
my $filename = 'some-file.txt';
my $content = do{local(@ARGV,$/)=$filename;<>};
my $content2 = do{local(@ARGV,$/)=$filename;<>};
my $content3 = do{local(@ARGV,$/)=$filename;<>};
print "After reading a file 3 times redirecting to STDIN: $.\n";
open (FILE, "<", $filename) or die $!;
print "After opening a file using dedicated file handle: $.\n";
while (<FILE>) {
print "read line: $.\n";
}
print "before close: $.\n";
close FILE;
print "after close: $.\n";
résulte en:
After reading a file 3 times redirecting to STDIN: 3
After opening a file using dedicated file handle: 3
read line: 1
read line: 2
(...)
read line: 46
before close: 46
after close: 0
La chose étrange est que le compteur de ligne $.
est augmenté de un pour chaque fichier. Il n'est pas réinitialisé et ne contient pas le nombre de lignes. Et il n'est pas remis à zéro lors de l'ouverture d'un autre fichier jusqu'à ce qu'au moins une ligne soit lue. Dans mon cas, je faisais quelque chose comme ça:
while($. < $skipLines) {<FILE>};
En raison de ce problème, la condition était fausse car le compteur de ligne n'a pas été réinitialisé correctement. Je ne sais pas s'il s'agit d'un bug ou simplement d'un code erroné ... Appelant égalementclose;
oder close STDIN;
n'aide pas non plus.
J'ai remplacé ce code illisible en utilisant open, string concatenation and close. Cependant, la solution publiée par Brad Gilbert fonctionne également puisqu'elle utilise à la place un descripteur de fichier explicite.
Les trois lignes du début peuvent être remplacées par:
my $content = do{local $/; open(my $f1, '<', $filename) or die $!; my $tmp1 = <$f1>; close $f1 or die $!; $tmp1};
my $content2 = do{local $/; open(my $f2, '<', $filename) or die $!; my $tmp2 = <$f2>; close $f2 or die $!; $tmp2};
my $content3 = do{local $/; open(my $f3, '<', $filename) or die $!; my $tmp3 = <$f3>; close $f3 or die $!; $tmp3};
qui ferme correctement le descripteur de fichier.