我使用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;
答案 0 :(得分:2)
我对Windows的工作原理知之甚少,所以也许有人可以提供更具体的答案,但是当在perl中的进程之间进行管道连接时,你需要小心避免意外的阻塞和死锁。在perlipc中讨论了各种问题场景。
在您的示例中,立即调用waitpid
会导致问题。一种可能性是孩子在读取输出之前无法退出,因此所有内容都会挂起,因为父节点不会读取输出。另一种可能性是,部分数据流作为waitpid
调用的一部分被关闭,这导致远程进程出现问题。
在任何情况下,最好在调用waitpid
之前阅读子进程的输出。