perl – 使用系统时信号传播到父级

前端之家收集整理的这篇文章主要介绍了perl – 使用系统时信号传播到父级前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我编写了一个包装器脚本,使用system()启动另一个脚本.子脚本捕获SIGINT并在内部处理异常.因此,它不应该在退出时将SIGINT传播给它的父级.但是,在某些情况下,父级仍然会收到SIGINT.例如(parent.pl):
use feature qw(say);
use strict;
use warnings;
use POSIX ();

my @data = (q(child.pl 'dummy'),q(child.pl),q(bash -c child.pl),q(sh -c child.pl));

for ( @data ) {
    say "Running command '$_'..";
    my $res = system $_;
    my $signal = $res & 127;
    my $rval = $res >> 8;
    say "Parent received return value: $rval";
    if ( $signal == POSIX::SIGINT ) {
        say "Parent received SIGINT";
    }
}

和child.pl:

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

eval {
    local $SIG{INT} = sub { die "Aborted by user.\n" };
    sleep 10;
};
if ( $@ ) {
    print "\n" . $@;
    exit 0;
}
say "Timed out..";
exit 1;

如果我在超时前按CTRL-C,输出如下:

Running command 'child.pl 'dummy''..
^C
Aborted by user.
Parent received return value: 0
Parent received SIGINT
Running command 'child.pl'..
^C
Aborted by user.
Parent received return value: 0
Running command 'bash -c child.pl'..
^C
Aborted by user.
Parent received return value: 0
Running command 'sh -c child.pl'..
^C
Aborted by user.
Parent received return value: 0
Parent received SIGINT

因此,在第一种情况和最后一种情况下,父节点接收SIGINT,而对于第二种和第三种情况,它不接收SIGINT.

这是什么原因?如何修复以使SIGINT不会传播给第一个和最后一个案例?

(我怀疑它与Shell的类型有关,即sh vs bash)

解决方法

首先,让我们知道正在执行的内容.
system($shell_command)

是的缩写

system({ "/bin/sh" } "/bin/sh","-c",$shell_command)

除非shell命令不包含shell元字符,但在这种情况下不包含空格

system($shell_command)

是的缩写

my @cmd = split(' ',$shell_command);
system({ $cmd[0] } @cmd)

因此,

system("child.pl 'dummy'")   is short for   system({ "/bin/sh" } "/bin/sh","child.pl 'dummy'")
system("child.pl")           is short for   system({ "child.pl" } "child.pl")
system("bash -c child.pl")   is short for   system({ "bash" } "bash","child.pl")
system("sh -c child.pl")     is short for   system({ "sh" } "sh","child.pl")

值得注意的是,bash将自己替换为child.pl,而不是在此特定情况下在单独的进程中生成它.这使得child.pl在第三种情况下成为parent.pl的直接子项(就像第二种情况一样).

其次,让我们知道Ctrl-C的作用.

按下Ctrl-C时,终端将SIGINT发送到以该终端为控制终端的每个进程.换句话说,SIGINT被发送到会话的每个进程.

通过添加系统可以看到(“ps -o pid,ppid,pgrp,sid,cmd”);到child.pl,我们的会话中有三到四个进程,具体取决于测试用例.

> child.pl:child.pl处理SIGINT.它没有被它杀死.
> shell在测试用例1和4中由parent.pl启动:shell被SIGINT杀死.
> parent.pl:系统相当于本地$SIG {INT} =’IGNORE’;,因此忽略了SIGINT.
>启动parent.pl的登录shell:它忽略了SIGINT,但我不知道为什么.我猜它是因为它是一个交互式shell.

所以,这就是你所观察到的:

>当parent.pl的(直接)子节点是child.pl [测试用例2和3]时,子节点(child.pl)不会死于SIGINT,因为它处理SIGINT.>当parent.pl的(直接)子节点是shell [测试用例1和4]时,子节点(shell)从SIGINT消失,因为非交互式shell不处理/忽略SIGINT.

原文链接:https://www.f2er.com/Perl/172810.html

猜你在找的Perl相关文章