如何从 IPC::Run3 测试退出状态

How to test the exit status from IPC::Run3

我正在尝试测试 Perl 模块 IPC::Run3,但无法检查命令是失败还是成功。
我知道如果参数有问题 IPC::Run3 会发出退出代码,但是如果参数没问题但命令不存在怎么办?我如何测试以下示例?

有子程序调用 Run3

sub runRun3 {

    my $cmd = shift;
    my ($stdout, $stderr);

    run3($cmd, \undef, $stdout, $stderr);

#   if( $? == -1 ) {
    if (! $stdout and ! $stderr) {
        die "Something is wrong";
    } else {
        print "OK \n";
    }

}

当执行下面的命令 $cmds[0] 时(*nix 系统的 ls 命令)它按预期打印 OK,但是使用命令 $cmds[1] 它只是说 No such file or directory at ./testrun3.pl line 18。 通过对退出代码的测试,我希望它打印 Something is wrong

#!/usr/bin/perl

use warnings;
use strict;

use IPC::Run3;

my @cmds = qw(ls silly);

runRun3($cmds[0]);
runRun3($cmds[1]);

或者在这种情况下 IPC::Run3 的最佳替代方案是什么?这只是过程的过度简化,但最终我想在更复杂的情况下捕获 STDERR 和 STDOUT。

谢谢。

需要注意的几点。

首先,对于直接问题,IPC::Run3 文档告诉我们

run3 throws an exception if the wrapped system call returned -1 or anything went wrong with run3's processing of filehandles. Otherwise it returns true. It leaves $? intact for inspection of exit and wait status.

您询问的错误属于此类,您需要eval调用以捕获该异常

use warnings 'all';
use strict;
use feature 'say';

my ($stdout, $stderr);

my @cmd = ("ls", "-l");

eval { run3 \@cmd, \undef, $stdout, $stderr };
if    ( $@        ) { print "Error: $@";                     }
elsif ( $? & 0x7F ) { say "Killed by signal ".( $? & 0x7F ); }
elsif ( $? >> 8   ) { say "Exited with error ".( $? >> 8 );  }
else                { say "Completed successfully";          }

您现在可以在 if ($@) { } 块内打印您自己的消息,当底层 system 无法执行的错误发生时。例如调用一个不存在的程序时。

此处 $@eval 相关,而 $?system 相关。因此,如果 run3 没有问题并且 $@ 为假,接下来我们检查 system 本身的状态,因此 $?。来自文档

Note that a true return value from run3 doesn't mean that the command had a successful exit code. Hence you should always check $?.

对于变量 $@$?,请参阅 General Variables in perlvar,以及 systemeval 页。

这个的最小版本是删除 eval(和 $@ 检查)并期望程序 die 如果 run3 有问题,应该很少见,并检查(并打印)$?.

的值

关于 run3 界面的注释。使用 \@cmd 它期望 @cmd 包含一个分解成单词的命令,第一个元素是程序和其余参数。在 $cmd 接口支持的字符串中编写命令与在数组中编写命令是有区别的。请参阅 system 了解说明。

哪种选择最适合您取决于您​​的确切需求。这里有一些选项。也许先尝试 IPC::System::Simple (but no STDERR on the platter). For cleanly capturing all kinds of output Capture::Tiny is great. On the other end there is IPC::Run 以获得更大的功率。