tags:

views:

396

answers:

5

I am trying change the stdout of the system function using select. But it does not seem to be working. The system output is getting displayed on console rather than getting redirected to the file.

use strict;
use warnings;

chdir "C:\\Documents and Settings\\" or die "cannot open the dir\n";
open FH, ">out.txt" or die "cannot open out.txt\n";
select FH or die " cannot change the stdout\n";
system "dir /a" ;

Although I can do system "dir /a > out.txt", I want to know why the above code is not working.

+1  A: 

I'm not sure 'select' is what you are looking for in this case. To redirect STDOUT to a file, you can do the following:

use strict;
use warnings;
use IO::Handle;
open FH, "> out.txt";
STDOUT->fdopen( \*FH, 'w' ) or die $!;
print "Hello world!\n";
system "dir /a";

Hope this helps!

ylebre
@ylebre, not working. Change the OUTPUT to FH in fdopen. Also, i wanted to to know why select was not working.
chappar
+1  A: 

Maybe this helps

jitter
+2  A: 

The problem with your code is that system command doesn't capture the output for you. You can use qx//:

use strict;
use warnings;

open my $fh, ">", "output.txt" or die $!;
my $oldfh= select $fh;
print qx/ls -a/;
select $oldfh;
close $fh or warn $!;

There are other options to run an external application and obtain read it's output, like the IPC::Open2 and IPC::Open3 modules. They're included in perl by default.

A side note: don't use globs for file handles: they are globals, and globals are evil. Use lexical variables instead (FH vs. $fh). Also, you should use the three argument open instead of two parameters, since the former is safer than the latter.

Igor
Igor, my argument is dir command should get the same stdout as that of perl program from which it was called. Since we have sort of duped stdout with a file, shouldn't the system's output go to the file?
chappar
No, it is not. When you run system("dir /a"), perl will run your shell (in your case, cmd.exe) as a forked process with "dir /a" as arguments. When you use qx//, perl returns the output of this forked process for you. Hope this clarifies a bit.
Igor
A: 

I reassign the file descriptors at the system (not Perl) level:

    sub reopen($$$) {
        open $_[0], $_[1]. '&='. fileno($_[2]) or die "failed to reopen: $!";
    }

    reopen *STDOUT,  '>', $new_stdout_handle;

Now anything that you fork will think $new_stdout_handle is standard output.

I pasted a full example to gist: http://gist.github.com/129407

jrockway
ysth
+3  A: 

The select function changes the default filehandle for output. It does not change STDOUT, which points to whatever it points to regardless if it is the default filehandle for output. If you want to change STDOUT, you have to do something like ylebre or Jon's answer.

When you start a child process, it gets the same standard output as the parent. It doesn't care what the default filehandle of the parent is though.

brian d foy