CTRL + C和Perl的system()函数 - 脚本不会被中断

时间:2017-11-06 12:23:03

标签: linux perl

我有一个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

有人能说清楚这里发生了什么吗?

2 个答案:

答案 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/;