To bardziej sugestia, jak tego NIE robić. Po prostu ciężko mi było znaleźć błąd w dość dużej aplikacji Perla. Większość modułów miała własne pliki konfiguracyjne. Aby odczytać pliki konfiguracyjne jako całość, znalazłem gdzieś w Internecie ten pojedynczy wiersz Perla:
# Bad! Don't do that!
my $content = do{local(@ARGV,$/)=$filename;<>};
Ponownie przypisuje separator linii, jak wyjaśniono wcześniej. Ale również ponownie przypisuje STDIN.
Miało to co najmniej jeden efekt uboczny, którego znalezienie kosztowało mnie wiele godzin: nie zamyka prawidłowo niejawnego uchwytu pliku (ponieważ w ogóle nie wywołuje close
).
Na przykład robiąc to:
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";
prowadzi do:
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
Dziwne jest to, że licznik linii $.
jest zwiększany dla każdego pliku o jeden. Nie jest resetowany i nie zawiera liczby wierszy. I nie jest resetowany do zera podczas otwierania innego pliku, dopóki nie zostanie odczytany przynajmniej jeden wiersz. W moim przypadku robiłem coś takiego:
while($. < $skipLines) {<FILE>};
Z powodu tego problemu warunek był fałszywy, ponieważ licznik linii nie został poprawnie zresetowany. Nie wiem, czy to błąd, czy po prostu zły kod ... Również wywołanie close;
odera close STDIN;
nie pomaga.
Zastąpiłem ten nieczytelny kod, używając open, konkatenacji ciągów i close. Jednak rozwiązanie opublikowane przez Brada Gilberta działa również, ponieważ zamiast tego używa jawnego uchwytu pliku.
Trzy wiersze na początku można zastąpić:
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};
który prawidłowo zamyka uchwyt pliku.