Return 使用 SIGINT 默认处理程序时来自 system() 的值

Return value from system() when using SIGINT default handler

当子进程从终端接收到 SIGINT 时,我遇到了来自 system() 的一些奇怪的 return 值。解释一下,从 Perl 脚本 parent.pl 我使用 system() 到 运行 另一个 Perl 脚本作为子进程,但我还需要 运行 通过 shell,所以我用了system 'sh', '-c', ...形式..所以子进程的父进程变成了sh进程,sh进程的父进程变成了parent.pl。另外,为了避免让 sh 进程接收到 SIGINT 信号,我设置了它。

例如,parent.pl:

use feature qw(say);
use strict;
use warnings;

for (1..3) {
    my $res = system 'sh', '-c', "trap '' INT; child$_.pl";
    say "Parent received return value: " . ($res >> 8);
}

其中 child1.pl:

local $SIG{INT} = "DEFAULT";
sleep 10;
say "Child timed out..";
exit 1;

child2.pl:

local $SIG{INT} = sub { die };
sleep 10;
say "Child timed out..";
exit 1;

child3.pl是:

eval {
    local $SIG{INT} = sub { die };
    sleep 10;
};
if ( $@ ) {
    print $@;
    exit 2;
}
say "Child timed out..";
exit 0;

如果我 运行 parent.pl(从命令行)并按 CTRL-C 中止每个子进程,输出为:

^CParent received return value: 130
^CDied at ./child2.pl line 7.
Parent received return value: 4
^CDied at ./child3.pl line 8.
Parent received return value: 2

现在,我想知道为什么案例 1 的 return 值为 130,案例 2 的 return 值为 4。

此外,如果能确切知道 "DEFAULT" 信号处理程序在这种情况下的作用,那就太好了。

注意:如果我将 sh 替换为 bash(并在 [=32 中捕获 SIGINT 而不是 INT =]).

另请参阅:

这个问题与您之前提出的 非常相似。

来自我的 bash 文档:

When a command terminates on a fatal signal N, bash uses the value of 128+N as the exit status.

SIGINT 通常为 2,因此 128 + 2 为 130。

Perl 的 die 通过检查 $!$? 未捕获的异常来计算出它的退出代码(所以,不是你使用 eval 的情况):

exit $! if $!;              # errno
exit $? >> 8 if $? >> 8;    # child exit status
exit 255;                   # last resort

请注意,在这种情况下,Perl 会以原样的值退出,而不是向上移动 8 位。

errno 值恰好是 4(参见 errno.h)。 $! 变量是一个具有不同字符串和数值的 dualvar。在数字上使用它(比如加零)来得到数字边:

use v5.10;

local $SIG{INT}=sub{
    say "numeric errno is ", $!+0;
    die
    };
sleep 10;
print q(timed out);
exit 1;

这会打印:

$ bash -c "perl errno.pl"
^Cnumeric errno is 4
Died at errno.pl line 6.
$ echo $?
4

打乱你的问题:

Also, it would be nice to know exactly what the "DEFAULT" signal handler does in this case.

将给定信号的处理程序设置为 "DEFAULT" 确认或恢复给定信号的默认信号处理程序,其操作取决于信号。详细信息可从 the signal(7) manual page 获得。 SIGINT 的默认处理程序终止进程。

Now, I would like to know why I get a return value of 130 for case 1, and a return value of 4 for case 2.

您的 child1 显式设置了 SIGINT 的默认处理程序,因此该信号导致其异常终止。 这样的进程没有常规意义上的退出代码。 shell 也接收 SIGINT,但它会捕获并忽略它。它为子进程(因此也为它自己)报告的退出状态反映了杀死子进程的信号(数字 2)。

另一方面,您的其他两个子进程 catch SIGINT 并正常终止作为响应。这些确实会产生退出代码,shell 将其传递给您(在捕获并忽略 SIGINT 之后)。 The documentation for die() 描述了在这种情况下如何确定退出代码,但最重要的是,如果您想使用特定代码退出,那么您应该使用 exit 而不是 die