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
=]).
另请参阅:
- perlipc
- 第 15 章,在 Programming Perl, 4th Edition
这个问题与您之前提出的 非常相似。
来自我的 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
。
当子进程从终端接收到 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
=]).
另请参阅:
- perlipc
- 第 15 章,在 Programming Perl, 4th Edition
这个问题与您之前提出的
来自我的 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
。