English 中文(简体)
How can I use Perl to start a Win32 program and redirect its output to stdout?
原标题:

I have a cross-platform Perl program that starts a win32 windows program on win, and a macosx appliaction on the mac.

I use system(), which on the mac makes the stdout of the invoked program, be written in the stdout of the Perl program, which is what i want.

On Windows, it seems like there is no way to get the stdout a Windows program. So as an alternative, I m having the program write to a logfile instead, and I d like Perl to read from the logfile (as it s being written to, the invoked program could run for an hour), and redirect that back to Perl s stdout, so that the experience on Win and Mac is the same.

Does anybody know how to actually do this in Perl? I m thinking:

  • fork the process
  • File::Tail the logfile, writing to stdout as data comes in
  • somehow figure out when the program actually finished running.

I can probably figure out #1 and #2, but don t know yet how to tackle #3.

最佳回答

Would the following fulfill your original intention: stdout of win32 program is also stdout of perl (or did I misunderstand your original question)?

// Win32 console application printing to stdout
#include <stdio.h>

int main(int argc, char* argv[])
{
    int idx;
    for (idx=0; idx < 10; idx++) {
        printf("Hello World!
");
        fflush(stdout);
    }
    return 0;
}

Perl program capturing stdout of windows program and redirecting to stdout:

use strict; use warnings;

my $cmd = "Debug/hello.exe";
open my $cmd_h, "$cmd |" or die "Cannot open pipe to  $cmd : $!";
print "Perl:$_" while <$cmd_h>;
close $cmd_h or die "Cannot close pipe to  $cmd : $!";
问题回答

If you need to capture the output your programs print to STDOUT, why don t you simply use backticks instead of system()?

my $stdout = `program_name`;
if ( $? ) {
    print "Child process had an error";
}

IPC::Run3 lets you provide stuff for stdin and capture stdout and stderr.

Have you read the docs for system? system does not let you capture STDOUT. qx does.

On the other hand, it does not look like you really want to capture STDOUT. It seems like you want the output from the program to appear in the same terminal window as the Perl program. If the program you are invoking on Windows does print its output to STDOUT and if you are running your Perl program in a cmd window, then this will happen naturally.

Capture the return value of the fork call to get the process ID of the child.

my $pid = fork();
if ($pid == 0) { # child
    system("command > logfile");
    exit 0;
}
# else parent
do {
    # ... apply File::Tail to logfile, print new output ... 
while (process_is_active($pid));

Then there are lots of ways to tell when the child has finished. Here are two:

# 1. kill 0, $pid
sub process_is_active {
    my ($pid) = @_;
    return kill 0, $pid;  # returns "number of processes successfully signalled"
}

Some systems do a better job of implementing kill 0,... than others.

# 2. non-blocking waitpid 
sub process_is_active {
    use POSIX  :sys_wait_h ;
    my ($pid) = @_;
    my $waitpid = waitpid $pid, WNOHANG;
    return $waitpid == $pid;
}

The second solution will only work once -- after waitpid detects that the process has finished and reaps it, it will return -1 if you call it again on that process.

Not sure quite what you mean by "get the stdout", but this correctly prints "foo" to standard out when run using perl.exe from the Windows command line:

perl -e "system  echo foo "

So I think as long as you run Perl in a command window, and don t try to mess with any of the stdout filehandles before calling system it should work.





相关问题
Why does my chdir to a filehandle not work in Perl?

When I try a "chdir" with a filehandle as argument, "chdir" returns 0 and a pwd returns still the same directory. Should that be so? I tried this, because in the documentation to chdir I found: "...

How do I use GetOptions to get the default argument?

I ve read the doc for GetOptions but I can t seem to find what I need... (maybe I am blind) What I want to do is to parse command line like this myperlscript.pl -mode [sth] [inputfile] I can use ...

Object-Oriented Perl constructor syntax and named parameters

I m a little confused about what is going on in Perl constructors. I found these two examples perldoc perlbot. package Foo; #In Perl, the constructor is just a subroutine called new. sub new { #I ...

Where can I find object-oriented Perl tutorials? [closed]

A Google search yields a number of results - but which ones are the best? The Perl site appears to contain two - perlboot and perltoot. I m reading these now, but what else is out there? Note: I ve ...

热门标签