When executing the following simplified code:
use strict; # [01]
use warnings FATAL => 'unopened'; # [02]
# [03]
my ($inHandle, $outHandle) = (\*STDIN, \*STDOUT); # [04]
print $outHandle "STDOUT 1\n"; # [05]
# [06]
# $outHandle re-assigned to outputA.txt ??? # [07]
open($outHandle, ">outputA.txt") or die ("A: $!\n"); # [08]
print $outHandle "FILE A\n"; # [09]
print "STDOUT? 2\n"; # [10]
print STDOUT "STDOUT 3\n"; # [11]
close $outHandle; # [12]
# [13]
# $outHandle is closed # [14]
print STDOUT "STDOUT 4\n"; # [15]
print "STDOUT? 5\n"; # [16]
print $outHandle "FILE CLOSED\n"; # [17]
# [18]
# $outHandle re-assigned to outputA.txt ??? # [19]
open($outHandle, ">outputB.txt") or die ("B: $!\n"); # [20]
print $outHandle "FILE B\n"; # [21]
close $outHandle; # [22]
I encounter these following odd behaviors:
$outputHandle
(line [13]), even when use warnings FATAL => 'unopened';
is used.STDOUT | outputA.txt | outputB.txt |
---|---|---|
STDOUT 1 | FILE A | FILE B |
STDOUT? 2 | ||
STDOUT 3 |
This is the output I expect assuming line [17] is commented out and doesn't raise the warnings FATAL => 'unopened'
STDOUT | outputA.txt | outputB.txt |
---|---|---|
STDOUT 1 | FILE A | FILE B |
STDOUT? 2 | ||
STDOUT 3 | ||
STDOUT 4 | ||
STDOUT? 5 |
As a side note:
When the standard output stream† gets redirected (reopened) to a file then there is no way to print to the console with it; what was meant to go there is now connected to that file instead. So once that was done then all other prints to STDOUT
, done one way or another, wind up in the file.
And then that filehandle gets closed; after that one cannot print to STDOUT
anymore.‡
So the first table is what one should expect.
I do get a warning when printing to an unopened filehandle, so for any and all prints to STDOUT
after it got closed. Edit ... without FATAL => 'unopened'
but with normal warnings
enabled, that is (how I tested for this answer). However, with that warning category alone there are no warnings for printing to closed filehandles (ones that had been initialized then closed). See this page.
Some notes:
A few pages in docs to study: open, and Playing with STDIN and STDOUT (old perlopentut), and open FILEHANDLE in perlfunc
There are ways to manipulate standard streams with control. One is to "dup" (duplicate) it, so after it's been redirected, used, and closed one can restore it. Some examples that come to mind: in posts on STDOUT and on redirection. (Note that $fh = \*STDOUT
creates an alias, so when one of them is changed so is the other.)
Or, in a separate scope (block will do nicely), do local *STDOUT;
and after that all mention of STDOUT
will work with this local copy. Once you leave the scope the global one gets restored.
Or you can use select
instead of messing with the STDOUT
per se.
Most of these are nicely summarized in a perl.com article. For more also see this page
"Three argument" open
is better: open my $fh, '<', $file ...
(and check or die $!
)
It's called a "handle," not a "handler"
† The file descriptor 1, for which Perl provides an opened STDOUT
filehandle (really *STDOUT
glob, but *
may be omitted when a filehandle is expected, or as a proper reference \*STDOUT
)
‡ Even if STDOUT
hasn't been first redirected, once it is closed there is no connection to standard output stream, and there is no simple way to reopen it as it had been. (There's of course ways to put things out on the terminal.)
In general, closing STDOUT
isn't a good idea, since many parties expect it to be open. For one, once fd1 is vacated other things may get it assigned, with bizarre trouble (see this post and Perl bug #23838). What if your program forks (in some way), and children processes inherit what they cannot possibly expect? What with the libraries that may get called in the next line? Etc.
There are better ways to manipulate STDOUT
, mentioned and linked in the text.
If you need STDOUT
to be gone, at least redirect it to /dev/null
(nul
on Windows) instead of outright closing it.