如何使用 Perl 启动 Win32 程序并将其输出重定向到 stdout?

发布于 2024-08-14 15:09:21 字数 462 浏览 6 评论 0原文

我有一个跨平台的 Perl 程序,可以在 win 上启动 win32 windows 程序,在 mac 上启动 macosx 应用程序。

我使用system(),它在mac上使被调用程序的stdout写入Perl程序的stdout中,这就是我想要的。

在 Windows 上,似乎没有办法获取 Windows 程序的标准输出。因此,作为替代方案,我让程序写入日志文件,并且我希望 Perl 从日志文件中读取(当写入时,调用的程序可以运行一个小时),并将其重定向回Perl的stdout,使得Win和Mac上的体验是一样的。

有人知道如何在 Perl 中实际做到这一点吗?我在想:

  • 分叉进程
  • File::Tail 日志文件,当数据进入时写入标准输出,以
  • 某种方式弄清楚程序何时实际完成运行。

我可能可以找出#1 和#2,但还不知道如何解决#3。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

东走西顾 2024-08-21 15:09:21

以下内容是否能满足您的初衷:win32 程序的 stdout 也是 perlstdout (或者我误解了您原来的问题)?

// 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!\n");
        fflush(stdout);
    }
    return 0;
}

Perl 程序捕获 Windows 程序的 stdout 并重定向到 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': $!";

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!\n");
        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': $!";
旧话新听 2024-08-21 15:09:21

如果您需要捕获程序打印到 STDOUT 的输出,为什么不简单地使用反引号而不是 system() 呢?

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

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";
}
淡淡離愁欲言轉身 2024-08-21 15:09:21

IPC::Run3 允许您为标准输入提供内容并捕获标准输出和标准错误。

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

撩人痒 2024-08-21 15:09:21

您是否阅读过 system 的文档? system 不允许您捕获STDOUTqx 确实如此。

另一方面,您似乎并不真正想要捕获STDOUT。您似乎希望程序的输出与 Perl 程序显示在同一终端窗口中。如果您在 Windows 上调用的程序确实将其输出打印到 STDOUT,并且您在 cmd 窗口中运行 Perl 程序,那么这会自然发生。

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.

山有枢 2024-08-21 15:09:21

捕获fork调用的返回值以获取子进程的进程ID。

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));

然后有很多方法可以判断孩子何时完成。这里有两个:

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

某些系统在实现 kill 0,... 方面比其他系统做得更好。

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

第二种解决方案只能工作一次——在 waitpid 检测到进程已完成并获取它之后,如果您在该进程上再次调用它,它将返回 -1

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.

够运 2024-08-21 15:09:21

不太清楚“获取标准输出”是什么意思,但是当从 Windows 命令行使用 perl.exe 运行时,这会正确地将“foo”打印到标准输出:

perl -e "system 'echo foo'"

所以我认为只要您在命令窗口中运行 Perl,并且在调用它应该工作之前,不要尝试弄乱任何标准输出文件句柄。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文