如何重定向创建自己的子项的控制台应用程序的输出并重定向其子项的输出?

时间:2011-04-26 16:19:39

标签: perl winapi

我使用Perl执行psexec并从控制台捕获输出。对我来说似乎很奇怪的是,当我用反引号执行命令时,它每次都能正确捕获输出。

例如,这个Perl脚本可以工作,我在很多不同的配置上使用了很多年:

use strict;
my @out;
@out = `psexec \\\\192.168.1.105 -u admin -p pass netstat -a`;

print @out;

此Perl脚本失败,似乎可靠地导致psexesvc挂起在远程系统上:

use IPC::Open2;

my($chld_out, $chld_in, $pid);
$pid = open2($chld_out, $chld_in, 'psexec \\\\192.168.1.105 -u admin -p pass netstat -a');

waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;
my $answer = <$chld_out>;

print "\n\n answer: $answer";

对我来说很奇怪的是,反推似乎从来没有任何问题。其他一切都有,包括examples in C++ from MSDN

我怀疑IPC :: Open2的问题和C ++中的示例(上面链接的)与我从命令shell(cmd.exe)和子进程重定向STDIN和STDOUT这一事实有关。 (psexec)在与远程系统通信时做同样的事情。

另外,在perldocs中我可以找到关于反引号如何工作的详细信息?我最感兴趣的是他们在Windows上的“内部”。

或者,在Perl源代码中我可以查看反引号的内部工作原理(这可能比我可以咬的更多,但是在这一点上值得一试)。

更新: 按照安迪的建议,我发现这有效:

use IPC::Open2;

my($chld_out, $chld_in, $pid);
$pid = open2($chld_out, $chld_in, 'psexec \\\\192.168.1.105 -u admin -p pass netstat -a');

my @answer = <$chld_out>;
print "\n\n answer: @answer";

waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;

1 个答案:

答案 0 :(得分:2)

我对Windows的工作原理知之甚少,所以也许有人可以提供更具体的答案,但是当在perl中的进程之间进行管道连接时,你需要小心避免意外的阻塞和死锁。在perlipc中讨论了各种问题场景。

在您的示例中,立即调用waitpid会导致问题。一种可能性是孩子在读取输出之前无法退出,因此所有内容都会挂起,因为父节点不会读取输出。另一种可能性是,部分数据流作为waitpid调用的一部分被关闭,这导致远程进程出现问题。

在任何情况下,最好在调用waitpid之前阅读子进程的输出。