Perl脚本,用于在外部可执行文件仍在运行时记录其输出和错误

Perl脚本,用于在外部可执行文件仍在运行时记录其输出和错误,perl,pipe,stdout,executable,stderr,Perl,Pipe,Stdout,Executable,Stderr,我有一个Perl脚本,它运行一个外部可执行文件。该可执行文件运行一段时间(有时是几秒钟,有时是一小时),可以向STDOUT和STDERR输出文本以及退出代码,这些都是必需的。下面的代码演示了第一次成功的外部可执行文件运行(带有一行注释的小bash脚本),然后是错误的退出状态(例如gs-ghostscript)。 我希望外部可执行文件将其标准输出给Perl脚本进行评估、过滤、格式化等,然后在外部文件仍在执行时将其记录到日志文件(也用于其他内容)。STDERR也很高兴能以同样的方式工作。 这个脚本可

我有一个Perl脚本,它运行一个外部可执行文件。该可执行文件运行一段时间(有时是几秒钟,有时是一小时),可以向STDOUT和STDERR输出文本以及退出代码,这些都是必需的。下面的代码演示了第一次成功的外部可执行文件运行(带有一行注释的小bash脚本),然后是错误的退出状态(例如gs-ghostscript)。 我希望外部可执行文件将其标准输出给Perl脚本进行评估、过滤、格式化等,然后在外部文件仍在执行时将其记录到日志文件(也用于其他内容)。STDERR也很高兴能以同样的方式工作。 这个脚本可以记录STDOUT中的所有内容,但只有在可执行文件完成之后。并且STDERR只直接记录,没有评估等。我不可能安装任何额外的Perl部分、模块等

我如何让我的Perl脚本从可执行文件中获取每一行(STDOUT+STDERR),同时将其吐出(不仅仅是在最后)以及出于其他目的的退出代码

#!/usr/bin/perl
@array_executable_and_parameters = "/home/username/perl/myexecutable.sh" ; #ls -lh ; for i in {1..5}; do echo X; sleep 1; done
@array_executable_and_parameters2= "gs aaa" ;
my $line;
chdir("/home/username/perl/");
$logFileName = "logfileforsomespecificinput.log";
open(LOGHANDLE, ">>$logFileName" );
open (STDERR, '>>', $logFileName);                  #Prints to logfile directly
#open (STDERR, '>>', <STDOUT>);                 #Prints to own STDOUT (screen or mailfile)

print LOGHANDLE "--------------OK run\n";
open CMD, '-|', @array_executable_and_parameters or die $@;
while (defined($line = <CMD>)) {                    #Logs all at once at end
    print LOGHANDLE "-----\$line=$line-----\n";
}
close CMD;
$returnCode1= $?>>8;
print LOGHANDLE "\$returnCode1=$returnCode1\n";

print LOGHANDLE "--------------BAD run\n";
open CMD2, '-|', @array_executable_and_parameters2 or die $@;
while (defined($line = <CMD2>)) {
    print LOGHANDLE "-----\$line=$line-----\n";
}
close CMD2;
$returnCode2= $?>>8;
print LOGHANDLE "\$returnCode2=$returnCode2\n";

close(LOGHANDLE);

特别是查看模块,如果不满意,那么。你需要涵盖很多细节,这些模块将使你的生活更加轻松。

好的,到目前为止,你已经开始工作了。可能有一些问题-不确定环境变量,如umask或语言相关的或推送等待/阻塞时的系统负载,或者如何用捕获所有状态变量来替换die。然而,就我而言,它似乎工作得很好。我们将看到它如何在真实系统上工作

#! /usr/bin/perl
BEGIN {
    push @INC, '/home/myusername/perl5/lib/perl5';          #Where the modules from Cpan are
}
use IPC::Run qw( start pump finish );

@array_executable_and_parameters = ();
push(@array_executable_and_parameters,"/home/myusername/perl/myexecutable.sh"); #ls -lh ; for i in {1..5}; do echo X; sleep 1; done
my $h = start \@array_executable_and_parameters, \undef, \$out, \$err ;
while (42) {
    pump $h;# while ($out or $err);
    if ($out eq '' and $err eq '') {last;}
    print "1A. \$out: $out\n";
    print "1A. \$err: $err\n";
    $out = "";
    $err = "";
}
finish $h or die "Command returned:\n\$?=$?\n\$@=$@\nKilled by=".( $? & 0x7F )."\nExit code=".( $? >> 8 )."\n" ;
print "1B. \$out: $out\n";
print "1B. \$err: $err\n";

关键是理解泵的阻塞是如何工作的。所有的手册和帮助都跳过了这一部分。因此,当pump在没有输出的情况下更进一步时,会出现一个无休止的过程是关键。

虽然我同意这个答案会因为包含一个简单的示例而变得更有用,但评审人员请注意,链接是指向建议解决该问题的模块的实际文档的,对于一些暂时性的博客帖子等来说,Metapan不太可能改变或消失。@SinanÜnür:除了那些链接的易变性之外,有很多原因可以避免只使用链接的解决方案,这应该作为评论发布。完整的答案应该包括对错误行为的解释,以及为什么任何链接都可能产生影响的原因。显然,如果还提供了示例代码,这是最好的。是的,看起来很有希望。但是我不能安装、使用外部代码、模块、依赖项等。难道没有一种简单的手动方法来实现相同的结果吗?@uldics你的意思是比重新发明轮子更简单?如果您知道,
打开我的$fh,“-|”,那么,…
在内部只是对
管道()
分叉()
关闭()
dup()
execl()
execve()
等的一系列调用,您就不必问了。但是你问,所以最好的建议是坚持推荐的模块。这不是一项简单的任务,而且有很多令人讨厌的bug。IPC::Cmd无法交错STDOUT和STDERR,IPC::Run3可能会等待完成(不允许与子流程交互),因此根据您的三个建议,我认为只有一个能够满足我的要求的是IPC:Run。我如何让它像我要求的那样运行?除了文件输出重定向之外,我没有看到其他例子。在我的例子中,它可以像打开管道一样工作吗?
#! /usr/bin/perl
BEGIN {
    push @INC, '/home/myusername/perl5/lib/perl5';          #Where the modules from Cpan are
}
use IPC::Run qw( start pump finish );

@array_executable_and_parameters = ();
push(@array_executable_and_parameters,"/home/myusername/perl/myexecutable.sh"); #ls -lh ; for i in {1..5}; do echo X; sleep 1; done
my $h = start \@array_executable_and_parameters, \undef, \$out, \$err ;
while (42) {
    pump $h;# while ($out or $err);
    if ($out eq '' and $err eq '') {last;}
    print "1A. \$out: $out\n";
    print "1A. \$err: $err\n";
    $out = "";
    $err = "";
}
finish $h or die "Command returned:\n\$?=$?\n\$@=$@\nKilled by=".( $? & 0x7F )."\nExit code=".( $? >> 8 )."\n" ;
print "1B. \$out: $out\n";
print "1B. \$err: $err\n";