在bash中捕获程序杀害

时间:2019-01-10 16:39:10

标签: c bash

我正在尝试的是,我的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

但是它什么也没做。任何建议或帮助都将受到高度赞赏。

1 个答案:

答案 0 :(得分:3)

Shell信号处理

  

我有一个杀死进程的小例子。

#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}}是进程终止。当它收到自己的信号时,它终止。您有两种避免这种情况的选择:

  1. 使该过程避免发信号本身。可能的途径是

    • 已发出信号通知特定过程,而不是其过程组中的所有过程

      SIGTERM
    • 已经记录了其原始进程组号,然后在杀死原始进程组之前将其置于新的进程组中。假设该流程还不是流程组负责人,则可能是:

      kill(a_positive_pid_different_from_mine, SIGTERM);
      
  2. 让进程自己注册信号的处理程序。例如,这将使进程忽略它收到的下一个pid_t original_pg = getpgid(0); setpgid(0, 0); kill(-original_pg, SIGTERM);

    SIGTERM

当然,至少在关心它们是否成功完成和/或完成时,您必须始终检查函数返回值并正确处理它们。为了清楚起见,上述代码段中省略了此类检查。