Esta é mais uma sugestão de como NÃO fazer isso. Acabei de encontrar um bug em um aplicativo Perl bastante grande. A maioria dos módulos tinha seus próprios arquivos de configuração. Para ler os arquivos de configuração como um todo, encontrei esta única linha do Perl em algum lugar da Internet:
# Bad! Don't do that!
my $content = do{local(@ARGV,$/)=$filename;<>};
Ele reatribui o separador de linha conforme explicado anteriormente. Mas também reatribui o STDIN.
Isso teve pelo menos um efeito colateral que me custou horas para descobrir: ele não fecha o identificador de arquivo implícito corretamente (uma vez que não chama close
nada).
Por exemplo, fazer isso:
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";
resulta em:
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
O estranho é que o contador de linha $.
é aumentado para cada arquivo em um. Não é redefinido e não contém o número de linhas. E não é redefinido para zero ao abrir outro arquivo até que pelo menos uma linha seja lida. No meu caso, eu estava fazendo algo assim:
while($. < $skipLines) {<FILE>};
Por causa desse problema, a condição era falsa porque o contador de linha não foi redefinido corretamente. Não sei se isso é um bug ou simplesmente um código errado ... Também chamar close;
oder close STDIN;
não ajuda.
Substituí esse código ilegível usando open, string concatenation e close. No entanto, a solução postada por Brad Gilbert também funciona, pois usa um identificador de arquivo explícito.
As três linhas no início podem ser substituídas por:
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};
que fecha corretamente o identificador de arquivo.