我有一个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");
Run Code Online (Sandbox Code Playgroud)
这是外部的"程序":
#!/bin/env bash
echo "Started $1"
sleep 3
echo "Finished $1"
Run Code Online (Sandbox Code Playgroud)
我启动了脚本并发出了CTRL + Z.然后我做了一个ps -o pid,pgrp,cmd列出进程信息.我可以看到脚本,它调用的bash shell和sleep命令都属于同一个进程组.在sleep执行时我也希望它是前台进程组.我在Linux,信号和终端上读了一下,发现CTRL + C应该向整个前台进程组发送一个中断,从而也终止了脚本.
我也试过用exec()而不是system().这样,脚本在触发CTRL + C时会停止,但它不会运行在test1之后.
任何人都可以了解这里发生的事情吗?
小智 6
你调查和理解过程组是很好的.解释这些通常是这样一个问题的难点部分.因此,您知道中断信号SIGINT应该发送到进程组中的所有进程,包括您的perl进程.
但SIGINT并不总是致命的.它可以被捕获或忽略.子进程在运行时system()忽略该函数SIGINT.此功能使您可以中断已损坏的子进程,而不会中断父进程.
在perlfunc中,描述system()说:
由于在执行"系统"期间忽略"SIGINT"和"SIGQUIT",如果您希望程序在收到这些信号时终止,则需要根据返回值自行安排.
Run Code Online (Sandbox Code Playgroud)@args = ("command", "arg1", "arg2"); system(@args) == 0 or die "system @args failed: $?"
这是你需要做的.检查返回值system(),并在子进程失败时采取您认为合适的任何操作.如果你想区别于SIGINT其他类型的失败,perlfunc中的下一段将有助于:
如果您想手动检查"系统"的故障,可以通过检查$来检查所有可能的故障模式?像这样:
Run Code Online (Sandbox Code Playgroud)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;
Run Code Online (Sandbox Code Playgroud)