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?

+3


source to share


2 answers


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

      

+3


source


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.

+1


source







All Articles