How Do I Point a File Handle to STDOUT (or Another File Handle) In Perl?

前端 未结 5 1808
不知归路
不知归路 2021-01-31 18:19

I want to make a quick script that writes to a file if a file is given, or stdout if no file is given. It would be much easier for me to do this if I could start the script by p

相关标签:
5条回答
  • 2021-01-31 18:33

    You could always just write the regular output to STDOUT and your debug statements to STDERR. Then if the user wants the output to go to a file they can just redirect STDOUT to the file on the command line.

    0 讨论(0)
  • 2021-01-31 18:44

    Some ways (globs):

    # Requires 2-arg open, unfortunately
    open(OUTPUT, "> ".($output || '-'))  or die;
    

    if ($output) {
       open(OUTPUT, '>', $output) or die;
    } else {
       *OUTPUT = *STDOUT;
    }
    

    if ($output) {
       open(OUTPUT, '>', $output) or die;
    } else {
       open(OUTPUT, '>&', \*STDOUT) or die;
    }
    

    Some ways (lexical var):

    # Requires 2-arg open, unfortunately
    open(my $fh, "> ".($output || '-'))  or die;
    

    my $fh;
    if ($output) {
       open($fh, '>', $output) or die;
    } else {
       $fh = \*STDOUT;
    }
    

    my $fh;
    if ($output) {
       open($fh, '>', $output) or die;
    } else {
       open($fh, '>&', \*STDOUT) or die;
    }
    

    Some ways (other):

    # Changes the default handle for <print "foo">.
    if ($output) {
       open(OUTPUT, '>', $output) or die;
       select(OUTPUT);
    }
    
    0 讨论(0)
  • 2021-01-31 18:44

    Nevermind. Figured it out. Throwing in an ampersand does the trick. Full working code is:
    open( OUTPUT, ( $output ? ">$output" : ">&STDOUT" ) );

    0 讨论(0)
  • 2021-01-31 18:52

    - is magic. Follow the convention or you violate the principle of least surprise.

    use autodie qw(:all);
    use Getopt::Long qw(GetOptions);
    GetOptions(\my %opt, 'out=s') or die 'usage';
    die 'usage' unless $opt{out};
    open my $handle, ">$opt{out}";
    

    perl foo -o blahblah        # opens file blahblah for writing
    perl foo -o -               # goes to STDOUT
    

    Related: Are there reasons to ever use the two-argument form of open(...) in Perl?

    0 讨论(0)
  • 2021-01-31 18:54

    For the reader's sake (since OP already "got it working"):

    The Perl documentation, "perlopentut" (perldoc perlopentut) gives examples of opening an alternate filehandle directed to STDOUT, but it uses bareword filehandles, and the two-arg version of open, both of which are somewhat ancient. Damian Conway's book "Perl Best Practices" (as well as Perl::Critic, which is based on Damian's book) emphasizes using three arg opens and lexical filehandles (my $foo style filehandles). chromatic's "Modern Perl" also briefly mentions using lexical filehandles, and discourages barewords where practical. The three arg open is considered to be a safer form, as it limits exposure to shell injections. While the specific case here is low risk, it's still a good habit to default to the three-arg open.

    It takes careful reading of the examples shown in Perl's open documentation (perldoc -f open), and a little interpretation to notice the correct placement of the ampersand character in opening a duplicate filahandle directed to STDOUT when using the three-arg version of open. One might errantly assume that this should work: open my $fh, '>', '&STDOUT' or die $!;, mostly because it looks like a format we're used to seeing (ampersand preceding a symbol name). But that syntax isn't what open needs, and we're used to seeing it in an entirely different context: certain subroutine calls.

    The correct way to open a dupe to STDOUT with the three arg open is to combine the > and the & into the same second argument, and leave STDOUT bare, like this:

    use Modern::Perl;
    
    open my $fh, '>&', STDOUT or die "Bleah: $!";
    
    say $fh 'Printing alternate filehandle "$fh" worked.';
    say 'Implicitly printing to "STDOUT" also works.';
    

    Or passing STDOUT to open as a reference to the typeglob:

    open my $fh, '>&', \*STDOUT or ...
    
    0 讨论(0)
提交回复
热议问题