File descriptors do not work as expected in Perl
I tried to initialize two file descriptors to NULL and then use it in my program.
This was my code:
my $fh1 = " ";
my $fh2 = " ";
open($fh1, ">", $fname1);
open($fh2, ">", $fname2);
print $fh1 "HI this is fh1";
Upon execution, my files contained this:
fname1 is empty
fname2 cointains
Hi this is fh1
What was the mistake?
Why is fname1 empty and fname2 contains a string, even though I haven't inserted any rows in fh2?
source to share
You have set $fh1
both $fh2
to the same value (whitespace, not NULL) and so they refer to the same base type glob for I / O.
Perl file descriptors are a special type of variable called glob or typeglob. In the old days of Perl 4, you always referred to glob as a string of characters, often as a single word. Horizons STDIN
, STDOUT
and STDERR
are relics of this simpler time.
Currently, you can (and usually should) use lexical file descriptors, but the underlying typeglob reference will still be present. For example, you can write
my $fh = 'STDOUT';
print $fh "hello world\n";
and this will do the same as
print STDOUT "hello world\n";
Now, if you pass an uninitialized scalar as the first argument to open
, Perl will assign an arbitrary type to it. You probably don't need to know what type it is in.
But if the argument open
has already been initialized, Perl uses typeglob with that argument value. So this piece of code will create and add data to the file:
my $fh = "FOO";
open $fh, '>', '/tmp/1';
print FOO "This is going into /tmp/1\n";
close $fh;
We can now look at your example. You set $fh1
both $fh2
to the same value - a string consisting of a space character. Thus, your call open
to $fh1
creates an association between the named character type " "
and the file descriptor for the output stream to $fname1
.
When you call open
in $fh2
, you reuse a named typeglob " "
that automatically closes another file descriptor with the same type glob ( $fh1
), same as you say open FOO, ">/tmp/1"; open FOO, ">/tmp/2"
, the second call open
will implicitly the close
first file descriptor.
Now you print to $fh1
which refers to the type glob with the name " "
that is associated with the output stream with the file $fname2
, and where the output goes.
Initialization error $fh1
and $fh2
. Just leave them undefined:
my ($fh1, $fh2);
open $fh1, ">", ... # assigns $fh1 to arbitrary typeglob
open $fh2, ">", ... # assigns $fh2 to different arbitrary typeglob
source to share
You shouldn't initialize your file descriptors at all, or Perl will try to use that value as a file descriptor instead of creating a new one. In this case, you opened $fname1
in the file descriptor ' '
(one space) and then opened $fname2
in the same file descriptor that closes $fname1
.
Instead of declaring file descriptors separately, it is best to declare them in a statement open
, for example
open my $fh1, '>', $fname1;
open my $fh2, '>', $fname2;
then there is less that can go wrong.
source to share