I tried initializing two file handles to NULL and later 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";
After executing, my files contained this:
fname1 is empty
fname2 cointains
Hi this is fh1
What was the mistake ?
Why is fname1 empty while fname2 contains a string, even though I haven't inserted any string in fh2?
You have set $fh1
and $fh2
to the same value (a space character, not NULL) and so they refer to the same underlying typeglob for I/O.
Filehandles in Perl are a special variable type called a glob or typeglob. In the old days of Perl 4, you always referred to a glob as a character string, often as a bareword. The barewords STDIN
, STDOUT
, and STDERR
are relics of this simpler time.
Nowadays, you can (and usually should) use lexical filehandles, but the underlying reference to a typeglob will still be there. For example, you can write
my $fh = 'STDOUT';
print $fh "hello world\n";
and this will do the exact same thing as
print STDOUT "hello world\n";
Now if you pass an uninitialized scalar as the first argument to open
, Perl will assign an arbitrary typeglob to it. You probably don't need to know which typeglob it is.
But if the argument to open
is already initialized, Perl uses the typeglob with that argument's value. So this snippet of code will create and add data to a file:
my $fh = "FOO";
open $fh, '>', '/tmp/1';
print FOO "This is going into /tmp/1\n";
close $fh;
Now we can look at your example. You have set $fh1
and $fh2
to the same value -- a string consisting of a space character. So your open
call to $fh1
creates an association between a typeglob named " "
and the file descriptor for the output stream to $fname1
.
When you call open
on $fh2
, you are reusing the typeglob named " "
, which will automatically close the other filehandle using the same typeglob ($fh1
), the same was as if you say open FOO, ">/tmp/1"; open FOO, ">/tmp/2"
, the second open
call will implicitly close
the first filehandle.
Now you are printing on $fh1
, which refers to the typeglob named " "
, which is associated with the output stream to file $fname2
, and that's where the output goes.
It was a mistake to initialize $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