让 Perl 返回正确的退出代码
Posted
技术标签:
【中文标题】让 Perl 返回正确的退出代码【英文标题】:Getting Perl to return the correct exit code 【发布时间】:2011-08-16 15:04:54 【问题描述】:我在 Ubuntu 11.04 上使用 Perl 5.10.1。我希望 Perl 执行一个 shell 脚本并使用与 shell 脚本退出相同的代码退出。但这对我不起作用...
system($runCmd) or die("Failed to run \"$runCmd\": $!");
我已经确认单独运行“$runCmd”会返回 255 的退出代码,但不会调用“die”子句。如何使用正确的代码退出,或者至少对于不成功的代码失败?
另一个次要要求是我希望将 $runCmd 的输出打印到屏幕上。
【问题讨论】:
【参考方案1】:正如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";
【讨论】:
system()
返回的值是一个整数,它编码子进程的退出值加上指示子进程如何退出的标志(正常终止、被信号杀死等)传递的值to exit()
只是退出值。
对,OP 希望“Perl 执行 shell 脚本并以与 shell 脚本退出相同的代码退出”,因此将 $exit_code
传递给 exit()
使程序以相同的退出退出代码作为通过将$runCmd
传递给shell 生成的退出代码。
程序 /bin/false 以退出值 1 退出。但 perl -e 'print system("/bin/false")'
打印 256。
@user5402:不一定。来自信息:“可移植程序不应假定‘false’的退出状态为 1,因为它在某些非 GNU 主机上大于 1。”我们都想要可移植的程序,不是吗? :)
@musicKk 我只是指出system()
返回的值是您传递给exit()
的值的256 倍。【参考方案2】:
如果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
附加到它。
注意$?
全局的右移八位。
致谢@musiKk:perl documentation on system()
说明如何正确检索实际退出状态。
【讨论】:
只是一个补充:你必须将system
的返回值右移八位才能得到$cmd
的返回值。 (perldoc.perl.org/functions/system.html)【参考方案3】:
system($runCmd) or die("Failed to run \"$runCmd\": $!");
与大多数 Perl 函数不同,system
在成功时返回 false,在失败时返回 true。我知道这完全是倒退,但事实就是如此。
你需要“system() and”而不是“system() or”。你可能想要$?
而不是$!
,尽管这有时会很棘手。
我对
有点反感system(...) && die
因为它搞砸了 || die
的所有其余部分,通常会在右侧形成连续的垂直双边距,所以我有时会写
system(...) == 0 || die
这样他们都再次正确排列。
【讨论】:
【参考方案4】:如果 system() 看似落后的问题困扰着您,您总是可以通过以下方式使其更可口:
my $err = system '/something/that/may/not/work';
if ($err)
warn "@[$! || 'undefined error']\n";
exit $err >> 8;
你的 $runCmd,顺便说一句,如果它打印到屏幕上(这是从命令行运行并且你没有重定向输出等)将打印到屏幕上。只是 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.
【讨论】:
【参考方案5】:我建议检查$?
变量(又名$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);
【讨论】:
以上是关于让 Perl 返回正确的退出代码的主要内容,如果未能解决你的问题,请参考以下文章