in reply to Re: possible bug in opening file handle to variable
in thread possible bug in opening file handle to variable

ikegami,

I am a little confused about what you are saying

File handles opened using open FILE, ">", \$var don't have file descriptors since there are no corresponding OS file handles. Since open FILE2, ">&FILE" means open a new file from the file descriptor of "FILE", it's no suprise it doesn't work. The code below demonstrates this and a fix.
It seems to apply only for opening file handles to strings instead of files.

The difference is shown in the output below (then followed by the code that generated it)

>perl out.pl d.d initial: fileno(*STDOUT) = 1 initial: fileno(*STDERR) = 2 redirected: fileno(*STDOUT) = 1 redirected: fileno(*STDERR) = 2 hello - this is contents of d.d testing stdout capture 1 testing stderr capture testing stdout capture 2 >perl out.pl initial: fileno(*STDOUT) = 1 initial: fileno(*STDERR) = 2 redirected: fileno(*STDOUT) = -1 redirected: fileno(*STDERR) = -1 hello - this is $captured_output testing stdout capture 1 testing stdout capture 2
Example code below:
#!/usr/bin/perl use strict; use FileHandle; my $use_file = shift; local *SAVED_STDOUT; local *SAVED_STDERR; open SAVED_STDOUT, ">&STDOUT" or die "couldn't save STDOUT: $!\n"; open SAVED_STDERR, ">&STDERR" or die "couldn't save STDERR: $!\n"; printf("\ninitial: fileno(*STDOUT) = %d\n", fileno(*STDOUT)); # 1 printf("initial: fileno(*STDERR) = %d\n", fileno(*STDERR)); # 2 my $captured_output = ""; # redirect standard out to file or string, as requested close STDOUT; if ($use_file) { open STDOUT, ">", "$use_file" or die "couldn't re-open STDOUT: $!\n"; } else { open STDOUT, ">", \$captured_output or die "couldn't re-open STDOUT: $!\n"; } close STDERR; open STDERR, ">&STDOUT" or die "couldn't re-open STDERR: $!\n"; printf SAVED_STDOUT "\nredirected: fileno(*STDOUT) = %d\n", fileno(*STDOUT); # 1 printf SAVED_STDOUT "redirected: fileno(*STDERR) = %d\n", fileno(*STDERR); # 2 select STDOUT; $|++; select STDERR; $|++; select STDOUT; print STDOUT "testing stdout capture 1\n"; print STDERR "testing stderr capture\n"; print STDOUT "testing stdout capture 2\n"; close STDOUT; open STDOUT, ">&SAVED_STDOUT"; close STDERR; open STDERR, ">&SAVED_STDERR"; if ($use_file) { printf SAVED_STDOUT "\n\nhello - this is contents of $use_file\n\n"; system("cat $use_file"); } else { printf "hello - this is \$captured_output\n\n"; printf STDERR $captured_output, "\n"; }

update adjusted indentation of code, but no changes to code

Replies are listed 'Best First'.
Re^3: possible bug in opening file handle to variable
by ikegami (Patriarch) on May 19, 2005 at 17:57 UTC
    It seems to apply only for opening file handles to strings instead of files.

    Indeed. I was trying to explain the reason for that in the bit that confused you. Let me try to explain better.

    Perl file handles are not the same as OS file handles. The OS file handles are called file descriptors.

    Perl file handles are only associated with a file descriptors when there's a real file (or pipe, etc) involved. That's not the case for file handles created using open(FILE, \$var), because the OS didn't create them. Those file handles exist solely within perl, so perl gives them the invalid file descriptor -1. fileno returns the file descriptor associated with a Perl file handle.

    open DUP, ">&FILE" is Perl's interface to a function that works on file descriptors, not Perl file handles. open DUP, ">&FILE" is more or less equivalent to the pseudocode DUP.fileno = dup(FILE.fileno); Therefore, it won't work on file handles opened using open(FILE, \$var) because they don't have corresponding file descriptor.