【问题标题】:Kill -INT not working on bash script with trap INT setKill -INT 在设置了陷阱 INT 的 bash 脚本上不起作用
【发布时间】:2017-11-05 08:53:30
【问题描述】:

考虑以下 bash 脚本s

#!/bin/bash
echo "Setting trap"
trap 'ctrl_c' INT
function ctrl_c() {
        echo "CTRL+C pressed"
        exit
}
sleep 1000

当调用它./s 时,它会休眠。如果您按 Ctrl+C,它会打印消息并退出。

现在调用它,打开另一个终端并杀死相应的 bash pid -INT 标志。它不起作用或做任何事情。为什么?

Kill without flags 有效,但不调用 ctrl_c() 函数。

【问题讨论】:

  • 发送kill -INT到你想停止的进程/PID,这里是sleep

标签: bash shell unix signals kill


【解决方案1】:

来自the POSIX standard for the shell

如果在 shell 等待执行前台命令的实用程序完成时接收到已设置陷阱的信号,则在前台命令完成之前,不应执行与该信号关联的陷阱。

为了验证这一点,我们可以在执行脚本的 shell 上运行 strace。在从另一个终端发送SIGINT 后,bash 只是注意到信号已被接收并返回等待其子进程 sleep 命令完成:

rt_sigaction(SIGINT, {0x808a550, [], 0}, {0x80a4600, [], 0}, 8) = 0
waitpid(-1, 0xbfb56324, 0)              = ? ERESTARTSYS
--- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=3556, si_uid=1000} ---
sigreturn({mask=[CHLD]})                = -1 EINTR (Interrupted system call)
waitpid(-1, 

要使kill 具有与Ctrl-C 相同的效果,您应该将SIGINT 发送到进程组。默认情况下,shell 会将新命令的每个进程放入自己的 pgrp:

$ ps -f -o pid,ppid,pgid,tty,comm -t pts/1
  PID  PPID  PGID TT       COMMAND
 3460  3447  3460 pts/1    bash
29087  3460 29087 pts/1     \_ foo.sh
29120 29087 29087 pts/1         \_ sleep

$ kill -2 -29087

现在陷阱运行,shell 退出:

waitpid(-1, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGINT}], 0) = 29120
--- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=3556, si_uid=1000} ---
sigreturn({mask=[CHLD]})                = 29120
...
write(1, "CTRL+C pressed\n", 15)        = 15
...
exit_group(0)                           = ?

【讨论】:

  • OK 简化我只是运行 ps -ef | grep(脚本名称)来获取 pid 然后我运行 kill -INT -pid 这里重要的是把 - 放在 pid 前面。非常感谢
【解决方案2】:

当我们使用 ps aux 命令查找 PID 值时,我们看到有 2 个进程,本程序和睡眠。如您所说,程序过程不会以 -INT 参数中断。但是,当 -2 或 -INT(相同含义)参数用于睡眠进程时,进程按预期中断。消息打印并退出。我不明白为什么主进程没有停止,但我想表明睡眠进程可以通过这种方法中断。希望对你有好处。

【讨论】:

  • sleepany 信号中断。
【解决方案3】:

sleep 不是内置的 shell:

$ which sleep
/bin/sleep

这意味着当您运行sleep 时,它将作为一个单独的子进程运行。创建子进程时,会从父进程复制各种内容(继承),其中之一就是信号掩码。注意:只有面具。所以如果你设置了:

 trap '' INT

那么sleep 会继承它 - 这意味着忽略信号。但是,在您的情况下,您希望 sleep(可能是用 C 编写的)执行 bash 函数。没有办法——首先是错误的语言。想象一下:它必须执行 bash 才能执行 bash 函数。

警告 - 有关信号处理的详细信息可能因平台而异。

可以将sleep 设为内置函数,请参阅here,但这可能麻烦多于其价值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 2011-07-10
    相关资源
    最近更新 更多