Perl脚本记录外部可执行文件输出和错误,但仍然运行

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Perl脚本记录外部可执行文件输出和错误,但仍然运行相关的知识,希望对你有一定的参考价值。

我有一个Perl脚本,它运行一个外部可执行文件。该可执行文件运行一段时间(有时是秒,有时是一小时),可以将文本吐出到STDOUT和STDERR以及退出代码,这些都是必需的。下面的代码演示了第一个成功的外部可执行文件运行(带有一行的小bash脚本 - 注释),然后出现状态不佳(例如gs - ghostscript)。我希望外部可执行文件将其STDOUT提供给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
";
open CMD, '-|', @array_executable_and_parameters or die $@;
while (defined($line = <CMD>)) {                    #Logs all at once at end
    print LOGHANDLE "-----$line=$line-----
";
}
close CMD;
$returnCode1= $?>>8;
print LOGHANDLE "$returnCode1=$returnCode1
";

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

close(LOGHANDLE);

拿2.在评论中提出好建议后我尝试了IPC :: Run。但是仍然没有按预期工作。我似乎错过了从开始(或泵?)到完成的循环如何工作,以及当我不知道最后的输出是什么时如何让它迭代 - 正如各处提到的例子。到目前为止,我现在有以下代码,但它不能逐行工作。它一次性吐出文件列表,然后等待外部循环完全打开以打印出所有X.我如何根据最初的需求来驯服它?

#! /usr/bin/perl
use IPC::Run qw( start pump finish );

@array_executable_and_parameters = ();
push(@array_executable_and_parameters,"/home/username/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 ;
pump $h;# while ($out or $err);
print "1A. $out: $out
";
print "1A. $err: $err
";
$out = "";
$err = "";
finish $h or die "Command returned:
$?=$?
$@=$@
Killed by=".( $? & 0x7F )."
Exit code=".( $? >> 8 )."
" ;
print "1B. $out: $out
";
print "1B. $err: $err
";
答案

看看IPC模块,特别是IPC::CmdIPC::Run,如果不满意,那么IPC::Run3。您需要涵盖很多细节,这些模块将使您的生活更轻松。

另一答案

好的,到目前为止已经让它工作了。可能有一些问题 - 不确定环境变量,如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
";
    print "1A. $err: $err
";
    $out = "";
    $err = "";
}
finish $h or die "Command returned:
$?=$?
$@=$@
Killed by=".( $? & 0x7F )."
Exit code=".( $? >> 8 )."
" ;
print "1B. $out: $out
";
print "1B. $err: $err
";

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

以上是关于Perl脚本记录外部可执行文件输出和错误,但仍然运行的主要内容,如果未能解决你的问题,请参考以下文章

从cron运行时,Perl脚本不会将STDOUT输出到文件

我的 perl 脚本如何调用和执行并后处理它

'perl' 不是内部或外部命令,也不是可运行的程序

Perl - 从外部进程直接输出到标准输出(避免缓冲)

linux可执行文件不工作,但脚本在python中工作

通过网页使 perl 脚本可执行