我正在尝试的是,我的c示例有kill()杀死了一个进程。但是我想通过bash脚本捕获该杀手,以便我的执行正确完成。
我有一个杀死进程的小例子。
#include <signal.h>
int main(void)
{
printf("before kill");
kill(0, SIGTERM); // 2265 is a process pid id
printf("after kill");
}
现在,我想在bash脚本中捕获此杀手。使用gcc命令生成二进制文件后,执行脚本,什么也没发生。
我的bash看起来像:
#!/usr/bin/env bash
term() {
./helloapp
echo "bash caught TERM"
}
trap term SIGTERM
但是它什么也没做。任何建议或帮助都将受到高度赞赏。
答案 0 :(得分:3)
我有一个杀死进程的小例子。
#include <signal.h> int main(void) { kill(0, SIGTERM); }
不,这不仅是尝试杀死 a 进程,它还试图杀死调用方进程组中的 all 进程。这是一个重要的区别,因为拥有一个发出信号的外壳陷阱可以保护外壳,但不能保护进程组中的任何其他进程。
我的bash看起来像:
#!/usr/bin/env bash term() { ./helloapp echo "bash caught TERM" } trap term SIGTERM
但是它什么也没做。
假设./helloapp
是将要发送信号的过程,则您完全误解了bash的信号处理风格。我怀疑这可能反映了对信号处理的普遍误解。
您已经编写了信号处理程序函数,就好像它为Java中的try
块内的命令提供了某种信号处理范围一样。但是信号与Java异常并不相似。它们是异步的,不在正常的控制流程之内。异常可能会导致控制转移,而这种转移原本是不可能的,但它们仍在整个程序流程中运行。信号处理不是这样。
Bash trap
命令不执行命名的shell函数。相反,它将注册为指定信号的处理程序。如果该Shell进程随后接收到指定信号之一,则该功能将运行,而不是该信号的默认行为。在这种情况下,如果进程向其传递SIGTERM
,则可以防止Shell自身终止。适当的语法应如下所示:
#!/usr/bin/env bash
# define signal handler
term_handler() {
echo "bash caught TERM but refuses to terminate"
}
# register signal handler
trap term SIGTERM
# run process that might send a signal
./helloapp
还请注意,shell会捕获来自任何源的信号,而不仅仅是来自其自身运行的命令的信号。
但是您在注释中澄清了,您真正想要的是在调用./helloapp
之后继续执行kill()
。在启动进程的shell中使用陷阱可以实现的目标并非遥不可及。陷阱处理传递给外壳本身而不是其他任何进程的信号。
很明显,您的流程似乎未通过kill()
的原因是它本身就是SIGTERM
所交付的流程之一,并且{{ 1}}是进程终止。当它收到自己的信号时,它终止。您有两种避免这种情况的选择:
使该过程避免发信号本身。可能的途径是
已发出信号通知特定过程,而不是其过程组中的所有过程
SIGTERM
已经记录了其原始进程组号,然后在杀死原始进程组之前将其置于新的进程组中。假设该流程还不是流程组负责人,则可能是:
kill(a_positive_pid_different_from_mine, SIGTERM);
让进程自己注册信号的处理程序。例如,这将使进程忽略它收到的下一个pid_t original_pg = getpgid(0);
setpgid(0, 0);
kill(-original_pg, SIGTERM);
:
SIGTERM
当然,至少在关心它们是否成功完成和/或完成时,您必须始终检查函数返回值并正确处理它们。为了清楚起见,上述代码段中省略了此类检查。