Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there rules which tell me what form of STDOUT/STDERR/SDTIN I have to choose?

Sometime I have to use the bareword "STDOUT", sometimes the bareword doesn't work and sometimes I can use the bareword or another form. Are there rules, which tell me when I have to choose on form and when another and when I can choose the form?

#!/usr/bin/env perl
use warnings;
use 5.12.0;
use utf8;


print STDOUT "Something\n";             # works

print \*STDOUT "Something\n";           # String found where operator expected 

print { STDOUT } "Something\n";         # Bareword "STDOUT" not allowed while "strict subs" in use 

print { \*STDOUT } "Something\n"        # works


my $fh;

$fh = -t STDOUT ? STDOUT : STDERR;      # Bareword "STDOUT"/"STDERR" not allowed while "strict subs" in use

$fh = -t STDOUT ? \*STDOUT : \*STDERR;  # works

$fh = -t \*STDOUT ? \*STDOUT : \*STDERR; # works 
like image 763
sid_com Avatar asked May 07 '12 08:05

sid_com


1 Answers

These are the rules according to my tests:

  1. when use strict subs is in effect, the bareword versions can't be passed as filehandles, presumably because they could be subroutine calls.

  2. The *STDOUT and \*STDOUT versions can be used to pass to functions all the time.

  3. passing one of them to a sub with foo STDOUT (without parentheses) breaks because perl assumes that is STDOUT->foo.

  4. Aside from cases 1 and 3, you can pass them to subs with the bareword verisons as well.

  5. for calls to print, printf etc, you must either use the bareword versions, or use {}. enclosing the filehandle in {} tells perl that yes the first argument is a filehandle, so you can use any form.

For these purposes -t counts as a sub, as do other -X tests that accept filehandles.

When you use {} with print or printf, the part inside {} is a code block; it is evaluated and the result is used as the filehandle. It works with those functions because they are treated specially by perl, in the same way as map and grep.

So follow these rules and you will be okay:

  • when printing to STDERR or STDOUT explcitly, use the bareword version:

    print STDERR "ERRORRRRR\n";
    
  • when using a filehandle in any other way, use the * version:

    my $isterm = -t *STDOUT;
    close(*STDERR);
    

I tested as far back as perl 5.8.7. This is as far back as I can go right now. The above should work for 5.6 as well.

like image 87
Michael Slade Avatar answered Oct 06 '22 01:10

Michael Slade