我已经减少了我面对MWE的问题。任何人都可以确认这是一个错误还是我遗漏了一些不成熟的东西?
平台:
第1步:创建一个名为demo.rb
ret = system("./segfault")
print "Return value: ", ret, "\n"
print "Exit status: ", ($?.exitstatus) ? $?.exitstatus : "nil", "\n"
print "Status code: ", $?.to_i, "\n"
puts "-----------------------------------"
ret = system("./segfault 2>&1")
print "Return value: ", ret, "\n"
print "Exit status: ", ($?.exitstatus) ? $?.exitstatus : "nil", "\n"
print "Status code: ", $?.to_i, "\n"
第2步:创建名为segfault.c
#include <string.h>
int main()
{
memset((char *)0x0, 1, 100);
return 1;
}
第3步:编译C程序。
gcc segfault.c -o segfault
第4步:运行Ruby脚本。
$ ruby segfault.rb
Return value: false
Exit status: nil
Status code: 139
-----------------------------------
sh: line 1: 8181 Segmentation fault (core dumped) ./segfault 2>&1
Return value: false
Exit status: 139
Status code: 35584
我无法理解为什么退出状态和状态代码会随stderr
重定向到stdout
而更改。有没有人对这种行为有合理的解释?
答案 0 :(得分:0)
您提供给系统的命令可以采用多种形式。如果它只是命令的路径,或者它是一个路径和一个参数数组,那么ruby forks和execs直接命令。
如果它更复杂,那么它执行它认为的标准shell并将命令传递给shell。
相关的原因在于exitstatus
的文档中说:
返回stat的返回码的最低有效位8位。仅在
exited?
为真时才可用。
exited?
的文档说
如果stat正常退出(例如使用exit()调用或完成程序),则返回true。
你的c二进制文件没有正常退出,所以在你的第一种情况下exited?
为false并且exitstatus返回nil在第二种情况下,当你的二进制文件仍然以相同的方式失败时,ruby执行的实际进程是你的shell实例,它正常退出。
就$?。to_i而言,我得到的结果不同。低8位包含诸如信号是否被引发以及高8位是否包含退出状态的信息。
在你的2个案例中我得到11和35584(139 <8),但是你的ruby版本似乎表现得像bash并且在信号值上增加了128(segfault是信号11)。
无论哪种方式,差异的原因是命令是否通过shell执行:shell看到失败的进程并将其信号值转换为退出状态(存储在高8位),而直接执行则没有退出状态和错误信息是低8位。
另外,您可以使用传递给系统的选项重定向输出,例如
system("mycommand", err: :out)
在你做的时候将stderr重定向到stdout