Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What type is STDOUT, and how do I optionally write to it?

Does STDOUT have a "type"?

printf STDERR ("STDOUT = %s\n", STDOUT);
printf STDERR ("\*STDOUT = %s\n", *STDOUT);
printf STDERR ("\\\*STDOUT = %s\n", \*STDOUT);

Produces:

STDOUT = STDOUT
*STDOUT = *main::STDOUT
\*STDOUT = GLOB(0x600078848)

I understand the *main::STDOUT and GLOB(0x600078848) entries. The "bareword" one leaves me curious.

I'm asking because I want to pass a file handle-like argument to a method call. In 'C', I'd use a file descriptor or a File *. I want it to default to STDOUT. What I've done is:

$OUT_FILE_HANDLE = \*STDOUT;
if(@ARGV > 0 ) {
    open($OUT_FILE_HANDLE, ">", "$ARGV[0]") or die $!;
}

It works, but I don't know exactly what I've done. Have I botched up STDOUT? I suspect I have "ruined" (overwritten) STDOUT, which is NOT what I want.

Please pardon the compound question; they seemed related.

like image 474
Erik Bennett Avatar asked Dec 22 '22 22:12

Erik Bennett


1 Answers

Create a lexical filehandle to be a copy of STDOUT and manipulate that as needed

sub manip_fh { 
    my ($fh) = @_;
    say $fh "hi";                              # goes to STDOUT
    open my $fh, '>', 'a_file.txt' or die $!;  # now it's to a file
    say $fh "hello";
}

open my $fh, '>&', STDOUT;  # via dup2

manip_fh($fh);

say "hi";  # still goes where STDOUT went before being dup-ed (terminal)

This new, independent, filehandle can then be reopened to another resource without affecting STDOUT. See open.

The $OUT_FILE_HANDLE = \*STDOUT; from the question creates an alias and so the STDOUT does indeed get changed when the "new" one changes. You can see that by printing the typeglob

our $NEW = \*STDOUT;  # "our" only for checks here, otherwise better "my"
say *{$main::NEW};    #--> *main::STDOUT

or by printing the IO slot from the symbol table for both

say for *{$main::NEW}{IO}, *{$main::{STDOUT}}{IO};

and seeing (that the object stringifies to) the same (eg IO::File=IO(0x1a8ca50)).

When it's duped using open with mode >& as in the first code snippet (but as global our) it prints *main::NEW, and its IO::File object is not the same as for STDOUT. (Make it a global our so that it is in the symbol table for these checks, but not for real use; it's much better having a my.)

like image 175
zdim Avatar answered Jan 05 '23 15:01

zdim