如果我有一个长期运行的system
命令,如apt-cache search <some query>
,有没有办法将命令行中SIGINT
发送的^C
转发给父Perl以这种方式处理所有子进程。
此示例没有所需的行为。信号将发送到子进程。
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use autodie;
# long running command on ubuntu, produces a ton of output.
# replace with your favorite long running command
system("apt-cache search hi");
print("Perl did not catch SIGINT even with autodie\n");
我试图寻找捕获由system("apt-cache search hi &")
创建的孩子的pid的方法,但无法找到,所以我尝试了fork
和{{1}进程和编写信号处理程序。这不起作用,因为exec
本身通过apt-cache
系统调用启动了一些进程。手动滚动一些逻辑来遍历流程树的一部分并清理
clone
我想基本上我想要的是确定#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use autodie;
my $cpid;
$SIG{INT} = sub {
kill 'KILL', $cpid;
exit;
};
# long running command on ubuntu, produces a ton of output.
# replace with your favorite long running command
$cpid = fork;
if ($cpid == 0) {
exec 'apt-cache', 'search', 'hi';
}
print "Perl did not catch SIGINT even with autodie\n";
启动的子进程是否由于system
等信号而退出,这样我就可以将Perl脚本清理干净了以这样一种方式来处理子进程并以这种方式收集进程管理的奇怪边缘情况。
答案 0 :(得分:6)
让孩子成为一个过程组的负责人,然后将信号发送给整个过程组。
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
use POSIX qw( setpgid );
my $child_pid;
$SIG{INT} = sub {
kill INT => -$child_pid if $child_pid;
exit(0x80 | 2); # 2 = SIGINT
};
my $child_pid = fork();
if (!$child_pid) {
setpgid($$);
exec 'apt-cache', 'search', 'hi';
}
WAIT: {
no autodie;
waitpid($child_pid, 0);
redo WAIT if $? == -1 and $!{EINTR};
die $! if $? == -1;
}
exit( ( $? >> 8 ) | ( 0x80 | ( $? & 0x7F ) ) );