in reply to possible bug in opening file handle to variable

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.

#!/usr/bin/perl -w use strict; use FileHandle; printf("fileno(*STDOUT) = %d\n", fileno(*STDOUT)); # 1 printf("fileno(*STDERR) = %d\n", fileno(*STDERR)); # 2 open SAVED_STDOUT, ">&STDOUT" or die "couldn't save STDOUT: $!\n"; open SAVED_STDERR, ">&STDERR" or die "couldn't save STDERR: $!\n"; print SAVED_STDOUT ""; # to suppress warning about possible typo print SAVED_STDERR ""; # to suppress warning about possible typo my $captured_output = ""; close STDOUT; 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"; *STDERR = *STDOUT; printf SAVED_STDOUT ("fileno(*STDOUT) = %d\n", fileno(*STDOUT)); # -1 printf SAVED_STDOUT ("fileno(*STDERR) = %d\n", fileno(*STDERR)); # -1 print "testing stdout capture 1\n"; print STDERR "testing stderr capture\n"; print "testing stdout capture 2\n"; close STDOUT; open STDOUT, ">&SAVED_STDOUT"; close STDERR; open STDERR, ">&SAVED_STDERR"; print $captured_output, "\n";

You could simplify the above code to:

#!/usr/bin/perl -w use strict; my $captured_output = ""; { local *STDOUT; open STDOUT, ">", \$captured_output or die "couldn't re-open STDOUT: $!\n"; local *STDERR = *STDOUT; print "testing stdout capture 1\n"; print STDERR "testing stderr capture\n"; print "testing stdout capture 2\n"; } print $captured_output, "\n";

Replies are listed 'Best First'.
Re^2: possible bug in opening file handle to variable
by Sandy (Curate) on May 19, 2005 at 17:16 UTC
    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:

    update adjusted indentation of code, but no changes to code

      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.