让Perl返回正确的退出代码

时间:2011-08-16 15:04:55

标签: perl

我在Ubuntu 11.04上使用Perl 5.10.1。我希望Perl执行shell脚本并使用shell脚本退出的相同代码退出。但这对我不起作用......

    system($runCmd) or die("Failed to run \"$runCmd\": $!");

我已经确认运行“$ runCmd”本身会返回退出代码255,但不会调用“die”子句。如何使用正确的代码退出,或者至少针对非成功代码失败?

另一个小要求是我希望$ runCmd的输出打印到屏幕上。

5 个答案:

答案 0 :(得分:11)

正如perldoc -f die所说,die没有给出特定的退出代码(只有非零退出代码)。为了得到你想要的东西,你需要这样的东西:

my $exit_code=system($runCmd);

if($exit_code!=0)
{
  print "Command $runCmd failed with an exit code of $exit_code.\n";
  exit($exit_code >> 8);
}
else
{
  print "Command $runCmd successful!\n";
}

答案 1 :(得分:9)

如果system返回255,则需要and条件。

system成功执行时返回零。此外,die将修改脚本的退出代码。而是warn并返回最后一个退出代码,如下所示:

system($cmd) and do {
    warn "Failed to run $cmd. Exit code is $?";
    exit $? >> 8;
};

为了捕获程序的输出,请使用反引号(`)运算符:

my $output = `$cmd`;

if ($?) {
   warn ...;
   exit $? >> 8;
}

反引号操作符仅捕获STDOUT,因此对于要捕获的所有错误消息(通常转到STDERR),请修改$cmd并将2>&1附加到其中。

注意$?全局右移8位。


致信@musiKk:perl documentation on system()说明了如何正确检索实际退出状态。

答案 2 :(得分:5)

  system($runCmd) or die("Failed to run \"$runCmd\": $!");

与大多数Perl函数不同,system在成功时返回false,在失败时返回true。这完全是我所知道的倒退,但事实就是如此。

你需要“system()和”not“system()或”。你可能希望$?不是$!,尽管这有时候会很棘手。

我对

有一点厌恶
system(...)                           && die

因为它搞砸了通常在右边连续垂直双边距的所有其余|| die,我有时会写

system(...) == 0                      || die

以便它们都能正确排列。

答案 3 :(得分:0)

如果系统()看似落后困扰你,你可以通过做类似的事情来使它变得更加可口:

my $err = system '/something/that/may/not/work';
if ($err) {
    warn "@{[$! || 'undefined error']}\n";
    exit $err >> 8;
}

你的$ runCmd,BTW,如果它打印到屏幕上(这是从命令行运行而你没有重定向输出等)将打印到屏幕上。只是IT会将其打印到屏幕上。 Perl不对此负责或知道(或关心)它的打印内容。如果这就是你想要的,并且你不想系统地分析或操纵$ runCmd的输出,你就是金色的。试试吧:

perl -e "system 'ls -Fahl'"

它也不会干扰你的$ runCmd的STDOUT。那也会到你的终端。例如:

$ perl -e "system 'ls -Fahl /dev/null/something' and die qq(fail: $! >> 8 == @{[$! >> 8]})"
ls: /dev/null/something: Not a directory
fail: 26205 >> 8 == 102 at -e line 1.

答案 4 :(得分:0)

我建议检查 $? 变量(也就是 $CHILD_ERROR 你是 use English; 双关语)。这样可以更彻底地检查您的 system() 调用结果。

要理解的是,$? 是一个 16 位字(艺术归功于 @ikegami):

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 15| 14| 13| 12| 11| 10|  9|  8|  7|  6|  5|  4|  3|  2|  1|  0|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

 \-----------------------------/ \-/ \-------------------------/
            Exit code            core     Signal that killed
            (0..255)            dumped         (0..127)
                                (0..1)
system($runCmd);
if ($? == -1) { # Failed to start program / error of the wait(2) system call
    die "Failed to execute '$runCmd': $!";
} elsif ($? & 127) { # Check for non-zero signal
    die "'$runCmd' died with signal", ($? & 127), ($? & 128) ? 'with' : 'without', " coredump";
} else { # No kill signal, check exit code.
    my $exit_code = $? >> 8; # This is the number you said to be 255.
    # print "'$runCmd' exited with value ", $exit_code, "\n";

    if ($exit_code == 255) {
        die("Failed to run \"$runCmd\": $!");
    } else {
        # can do additional checks for other exit codes if desired
    }
    exit $exit_code;
}


如果您真的不想弄乱 $?,还有一个值得注意的“替代方案”。基本上,只需使用 IPC::System::Simple。请注意,它不是核心模块,因此您需要安装它。

使用起来很简单:

use IPC::System::Simple qw(system);  # system() will now die properly

my $exit_value = system($runCmd);
my $exit_value2 = system($runCmd,@args);  # Alternative form that avoids shell if @args

如果您不想覆盖 system,您可以改用 run

use IPC::System::Simple qw(run);

my $exit_value = run($runCmd);
my $exit_value2 = run($runCmd,@args);