Perl:在IPC::Run中检索进程的输出
我已经在模块中运行了一些命令,一切都很好,只是我无法访问输出(STDOUT、STDERR),进程生成并被重定向到变量中。有没有办法在错误处理中检索这些错误Perl:在IPC::Run中检索进程的输出,perl,error-handling,Perl,Error Handling,我已经在模块中运行了一些命令,一切都很好,只是我无法访问输出(STDOUT、STDERR),进程生成并被重定向到变量中。有没有办法在错误处理中检索这些错误 @commands = (); foreach my $id (1..3) { push @commands, ["perl", "script" . $id . ".pl"]; } foreach my $cmd (@commands) { my $out = ""; my $err = ""; my $h = harne
@commands = ();
foreach my $id (1..3) {
push @commands, ["perl", "script" . $id . ".pl"];
}
foreach my $cmd (@commands) {
my $out = "";
my $err = "";
my $h = harness $cmd, \undef, \$out, \$err, timeout(12,exception => {name => 'timeout'});
eval {
run $h;
};
if ($@) {
my $err_msg = $@; # save in case another error happens
print "$out\n";
print "$err\n";
$h->kill_kill;
}
}
我现在不需要任何输入,我只需要执行它并获得输出
编辑
我一直在运行perl脚本对其进行测试,如下所示:
for (my $i = 0; $i < 10; $i++) {
sleep 1;
print "Hello from script 1 " . localtime() . "\n";
}
for(我的$i=0;$i<10;$i++){
睡眠1;
打印“Hello from script 1”.localtime()。“\n”;
}
我有3个不同时间的脚本,第3个脚本需要20秒才能完成,这比我在计时器中的12个脚本要多。正如@ysth所指出的,您没有得到任何输出的原因是,与命令
$cmd
对应的进程的STDOUT
和STDERR
没有行缓冲,而是块缓冲。因此,所有输出都收集在一个缓冲区中,该缓冲区在缓冲区已满或显式刷新之前不会显示(打印)。但是,当您的命令超时时,所有输出仍在缓冲区中,尚未刷新,因此收集到父进程(脚本)中的变量$out
还请注意,由于您的$cmd
脚本是一个Perl脚本,因此此行为记录在:
$|
如果设置为非零,则在每次写入后立即强制刷新
或在当前选定的输出通道上打印。默认值为0
(无论通道是否真的由系统缓冲或
not;$|只告诉您是否已显式要求Perl刷新
每次写入后)STDOUT通常在输出为
到终端和缓冲块,否则
文档页面中还记录了以下问题(程序未连接到终端或tty):
交互式应用程序通常针对人的使用进行优化。这个可以
通过以下模块帮助或阻碍与他们互动:
IPC::运行。通常,程序在检测到错误时会改变其行为
假设stdin、stdout或stderr未连接到tty
它们正在批处理模式下运行。这是有帮助还是有伤害
取决于更改的优化。而且通常没有办法
告诉你一个程序在这些方面做了什么,而不是尝试和错误
偶尔,阅读源代码。这包括不同的版本
以及相同程序的实现
文档还列出了一组可能的解决方法,包括使用
然后,针对特定情况的一种解决方案是在脚本开头显式地将STDOUT
行缓冲:
STDOUT->autoflush(1); # Make STDOUT line buffered
# Alternatively use: $| = 1;
for (my $i = 0; $i < 10; $i++) {
sleep 1;
print "Hello from script 1 " . localtime() . "\n";
}
你是说
$out
和$err
?如果$cmd
在超时之前生成任何输出,则这些选项应可用。你确定命令超时了吗?注意:除非有超时,否则脚本不会打印任何内容。是的,我指的是那些。嗯,我没有把全部代码放在那里,这只是主要部分。我正在运行3个脚本,打印某物并进入睡眠状态,我将其中一个脚本设置为比计时器运行的时间更长。前2个打印得很好,但第3个被计时器捕捉并退出。但是输出不可用。。。我在使用Fork管理器,所以我没有写全部内容,因为它可能会变得混乱。您能否提供第三个脚本的示例,以便我们可以尝试复制?如果您没有看到第三个脚本的任何输出,它可能正在被缓冲。您是否在未超时时获得输出?@heatheice感谢您的更新。尝试将STDOUT->autoflush(1)
放在脚本开头。根据“如果输出到终端,则标准输出通常是行缓冲的,否则块缓冲的”,使用您的解决方案确实解决了我的问题。但是我仍然会有一个问题,因为我将来不会只使用perl脚本。是否有其他模块将输出直接保存到处理程序或类似程序?我尝试过使用IO::Handler,但我没有让它工作……也许你也可以尝试愚弄正在运行的脚本,让它们相信它是通过使用Nit中描述的伪终端连接到一个真正的tty:print“…”
技术上打印到select()
返回的句柄,所以select()->autoflush(1)
比STDOUT->autoflush(1)更有意义代码>。当然,select()->autoflush(1)
也可以写成$|=1
@ikegami谢谢你的评论!知道这一点很好,但从OP的脚本中应该(?)非常清楚,它正试图输出到STDOUT(因此所选句柄对于它们的情况确实是STDOUT),因此我不会像您建议的那样用更“正确”的方法更新我的答案。我认为它包含了足够的细节,我想避免进一步的混乱/分心,但如果可以的话,你可以保留评论。就像我说的,这只是一个谎言。
my $h = harness $cmd, \undef, '>pty>', \$out,
timeout(12, exception => {name => 'timeout'});
eval {
run $h;
};