通过 Ctrl+C 控制取消哪个进程

通过 Ctrl+C 控制取消哪个进程

我有一张 Live CD,可以启动 Linux 并运行一个小型 Bash 脚本。该脚本搜索并运行第二个程序(通常是编译后的 C++ 二进制文件)。

您应该能够通过按Ctrl+中止第二个程序C。什么应该发生的情况是第二个程序停止了,Bash 脚本继续运行清理。什么实际上发生的情况是主应用程序和 Bash 脚本都终止。这是一个问题。

所以我使用trap内置命令告诉 Bash 忽略 SIGINT。现在Ctrl+C终止了 C++ 应用程序,但 Bash 继续运行。伟大的。

哦,是的...有时“第二个应用程序”是另一个 Bash 脚本。并且在情况下,Ctrl+C现在做什么都没有

Ctrl显然,我对这个东西如何工作的理解是错误的......当用户按+时,如何控制哪个进程获得 SIGINT C?我想将此信号定向到一个具体过程

答案1

经过很多很多个小时的互联网搜索,我找到了答案。

  1. Linux 有一个概念进程组

  2. TTY 驱动程序有一个前台进程组的概念。

  3. 当您按Ctrl+时C,TTY 会发送SIGINT每个过程在前台进程组中。 (也可以看看这个博客条目.)

这就是为什么编译的二进制文件启动它的脚本都被破坏了。事实上我只想让主应用程序接收这个信号,不是启动脚本。

现在解决方案很明显:我们需要将应用程序放入一个新的进程组中,并使其成为该 TTY 的前台进程组。显然执行此操作的命令是

setsid -c <applcation>

仅此而已。现在,当用户按下Ctrl+时C,SIGINT 将被发送到应用程序(及其可能拥有的任何子应用程序),而不是其他任何人。这就是我想要的。

  • setsid本身将应用程序放入一个新的进程组中(实际上,一个全新的“会话”,显然是一组进程组)。

  • 添加该-c标志使这个新进程组成为当前 TTY 的“前台”进程组。 (即,SIGINT当您按Ctrl+时就会出现C

我见过很多关于 Bash 何时在新进程组中运行或不运行进程的相互矛盾的信息。 (特别是,“交互式”和“非交互式”shell 似乎有所不同。)我已经看到了一些建议,您也许可以使用它巧妙的管道诡计... 我不知道。但上面的方法似乎对我有用。

答案2

在您的启动 bash 脚本中。

  • 跟踪第二个程序的PID

  • 捕获信号

  • 当您捕获到 SIGINT 时,将 SIGINT 发送到第二个程序 PID

答案3

正如我在 f01 的评论中提到的,您应该向子进程发送 SIGTERM。这里有几个脚本展示了如何捕获 ^C 并向子进程发送信号。

首先是家长。

陷阱测试

#!/bin/bash

# trap test
# Written by PM 2Ring 2014.10.23

myname=$(basename "$0")
child=sleeploop

set_trap()
{
    sig=$1
    msg="echo -e \"\n$myname received ^C, sending $sig to $child, $pid\""
    trap "$msg; kill -s $sig $pid" SIGINT
}
trap "echo \"bye from $myname\"" EXIT

echo "running $child..."
./$child 5  &
pid=$!

# set_trap SIGINT
set_trap SIGTERM
echo "$child pid = $pid"

wait $pid
echo "$myname finished waiting"

而现在,孩子。

睡眠循环

#!/bin/bash

# child script for traptest
# Written by PM 2Ring 2014.10.23

myname=$(basename "$0")
delay="$1"

set_trap()
{
    sig=$1
    trap "echo -e '\n$myname received $sig signal';exit 0" $sig
}

trap "echo \"bye from $myname\"" EXIT
set_trap SIGTERM
set_trap SIGINT

#Select sleep mode
if false
then
    echo "Using foreground sleep"
    Sleep()
    {
        sleep $delay
    }
else
    echo "Using background sleep"
    Sleep()
    {
        sleep "$delay" &
        wait $!
    }
fi

#Time to snooze :)
for ((i=0; i<5; i++));
do
    echo "$i: sleeping for $delay"
    Sleep
done

echo "$myname terminated normally"

如果 traptest 发送 SIGTERM ,事情表现得很好,但如果 traptest 发送 SIGINT ,那么 sleeploop 永远不会看到它。

如果 sleeploop 捕获 SIGTERM,并且睡眠模式为前台,那么它无法响应该信号,直到从当前睡眠中唤醒。但如果睡眠模式是后台,它会立即响应。

相关内容