我有一个Perl脚本,它按顺序使用system()
函数启动某些程序。当脚本正在运行并且程序正在运行时,我输入CTRL + C.我希望程序终止(发生),但我也希望脚本终止(这不会发生)。
我已经构建了一个最小的工作示例。这是Perl脚本:
#!/bin/env perl
sub run_the_test {
local($name, $_) = @_;
print "Starting $name\n";
return system("program.bash $name");
}
&run_the_test("test1");
&run_the_test("test2");
&run_the_test("test3");
这是外部的“程序”:
#!/bin/env bash
echo "Started $1"
sleep 3
echo "Finished $1"
我启动了脚本并发出了CTRL + Z.然后我做了ps -o pid,pgrp,cmd
列出了进程信息。我可以看到脚本,它调用的bash shell和sleep命令都属于同一个进程组。当sleep
正在执行时,我也希望它是前台进程组。我在Linux,信号和终端上读了一下,发现CTRL + C应该向整个前台进程组发送一个中断,从而也终止了脚本。
我也尝试使用exec()
代替system()
。这样,脚本在触发CTRL + C时会停止,但它不会超过 test1 。
有人能说清楚这里发生了什么吗?
答案 0 :(得分:6)
您调查并了解流程组是件好事。解释这些通常是这样一个问题的难点部分。因此,您知道中断信号SIGINT
应该发送到流程组中的所有流程,包括您的perl
流程。
但是SIGINT
并不总是致命的。它可以被捕获或忽略。子进程正在运行时system()
函数忽略SIGINT
。此功能使您可以中断已经坏的子进程,而不会杀死父进程。
在perlfunc中,system()
的描述说:
由于在执行期间忽略“SIGINT”和“SIGQUIT” “系统”,如果您希望您的程序在收到时终止 您需要根据这些信号自行安排 返回值。
@args = ("command", "arg1", "arg2"); system(@args) == 0 or die "system @args failed: $?"
这是你需要做的。检查system()
的返回值,并在子进程失败时采取您认为合适的任何操作。如果您想将SIGINT
与其他类型的失败区分开来,perlfunc中的下一段将有所帮助:
如果您想手动检查“系统”的故障,可以查看 通过检查$所有可能的故障模式?像这样:
if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } else { printf "child exited with value %d\n", $? >> 8; }
例如,您可以在run_the_test
中执行此操作:
my $r = system("program.bash $name");
die "Test interrupted, giving up" if ($? & 127) == 2;
return $r;
答案 1 :(得分:0)
有类似的问题,使用系统和管道。 CTRL-C 不起作用。 以下解决了它:
使用 sigtrap qw/die normal-signals/;