There are system files handles (called file descriptors, or "fd"), and there are Perl file handles. Perl file handles usually wrap a system file handles, but this isn't always the case. For example, open(my $fh, '<', \$buf)
creates a Perl handle that isn't associated with any system file handle.
Other processes don't know anything about your process's variables, so they don't know anything about Perl file handles. Whatever handle is opened as fd 0 will be used as STDIN, fd 1 as STDOUT, and fd 2 as STDERR.[1]
When open
is passed an existing Perl handle, this handle will be closed. If creating a new system file handle, it will be either be given the same number as the original fd (if the original handle had one) or the lowest available number (if it didn't).[2]
So, when you use open(*STDIN, ...)
, the new handle associated with *STDIN{IO}
will also be fd 0.
$ perl -e'
CORE::say fileno(*STDIN);
open(*STDIN, "<", "/dev/null") or die $!;
CORE::say fileno(*STDIN);
'
0
0
cat
, reading from fd 0, will therefore notice the change.
local *STDIN
creates a backup of the glob and associated *STDIN
with a fresh glob. The original *STDIN
is still in memory, so no resources associated with *STDIN
are freed. This means that any file handle associated with *STDIN
is still open.
When you use open(local *STDIN, ...)
, the new fd will have the lowest number available. fd 0 is still being used by the original *STDIN
somewhere in memory, so fd 0 is not available. Maybe fd 3 will be the first available fd this time (1 and 2 being used by STDOUT and STDERR).
$ perl -e'
CORE::say fileno(*STDIN);
{
open(local *STDIN, "<", "/dev/null") or die $!;
CORE::say fileno(*STDIN);
}
CORE::say fileno(*STDIN);
'
0
3
0
cat
, reading from fd 0, will read from the original handle.
Perl could make it so whatever handles are associated with STDIN, STDOUT and STDERR become fd 0, 1 and 2 before executing cat
, but it doesn't. This is left to you.
While I'm describing how things work in unixy systems, things work similarly in Windows.
In the situation where open
is passed a handle that wraps a system file handle and a new system file handle is also being created, the internal mechanism used on unixy system is the following:
- A new fd is created using
open
. It will have the lowest available number.
dup2
is used to create a duplicate of the new fd with the same number as the original fd.
- The fd created by
open
is closed.
This means the original fd isn't closed if an error occurs.