8

I'm working in a program where the user can pass a -o file option, and output should be then directed to that file. Otherwise, it should go to stdout.

To retrieve the option I'm using the module getopt long, and that's not the problem. The problem is that I want to create a file handle with that file or assign stdout to it if the option was not set.

if ($opt) {
    open OUTPUT, ">", $file;
} else {
    open OUTPUT, # ???
}

That's because this way, later in my code I can just:

print OUTPUT "...";

Without worrying if OUTPUT is stdout or a file the user specified. Is this possible? If I'm doing a bad design here, please let me know.

cmre
  • 83
  • 1
  • 3

3 Answers3

7

This would be a good example on how to use select.

use strict;
use warnings;
use autodie;

my $fh;
if ($opt) {
    open $fh, '>', $file;
    select $fh;
}

print "This goes to the file if $opt is defined, otherwise to STDOUT."
TLP
  • 66,756
  • 10
  • 92
  • 149
  • 1
    Nice TLP, thanks a lot. There still many things I need to learn about Perl... However, I'm not sure if this will work inside a `while (<>)`, it's not my case but just thinking about it. Reopening stdout seems to be a better option in these cases, considering I'll have to label the print anyway. – cmre Aug 14 '11 at 19:35
  • @cmre Oh, you edited your comment. Well, this will work just as well as reopening STDOUT. `print STDOUT "foo"` is essentially the same as `print "foo"`, so you do not need to specify the filehandle. I'm not quite sure what your concern is, but you should use the solution you feel comfortable with. – TLP Aug 14 '11 at 19:43
  • Yeah, just edited it, sorry. The concern is that `print "something"` inside a `while (<>) {...}` will output it to the file selected, right? Or maybe not, I'm just beginning with Perl and now it's becomes really confusing :P – cmre Aug 14 '11 at 19:48
  • @cmre What I mean is, with this solution, you do not need to use `print OUTPUT`, you can just use `print`. – TLP Aug 14 '11 at 19:49
  • Eh, yes, `print "something"` will print to STDOUT, or the currently `select`ed filehandle, no matter if you are inside a while loop or not. Being inside a loop does not matter. – TLP Aug 14 '11 at 19:53
  • Oh, I got it. Again sorry, as I said I'm just confused: I though `print` inside `<>` would print things to a file given as argument, but this is what happens when using the `$^I` variable. I started using Perl for some tasks I've been doing with sed for years, so I use `-i` frequently. – cmre Aug 14 '11 at 19:56
  • 1
    @cmre <> is for INPUT. select() and print() are for OUTPUT. They are not related. – tadmc Aug 14 '11 at 21:44
4

Look at the open documentation. The easiest is to reopen STDOUT itself and not use a filehandle in your code.

if ($opt) {
    open(STDOUT, ">", $file);
}
...

print "this goes to $file or STDOUT\n";

(Add some error checking of course.)

Mat
  • 202,337
  • 40
  • 393
  • 406
  • What if the program prints something to stdout anyway, while some other output (e.g. shell commands) goes to a file, or, optionally, to stdout as well? – Ale Jul 09 '21 at 08:11
0

A constant item such as OUTPUT cannot be assigned. Using a variable such as $output works better. For example:

my ($output, $display_filename);
if ($opt)
{
    if ($opt eq '-')
    {
        $display_filename = 'stdout';
        $output = *STDOUT;
    }
    else
    {
        $display_filename = $opt;
        open($output, '>', $opt) or
            die("Cannot open $opt for writing: $!\n");
    }
}

That way the program can print to standard output and/or to an output file:

print $output "This might go to a file\n";
print "Data written to $display_filename\n" if ($verbose);
Ale
  • 887
  • 10
  • 14