我有一张 Live CD,可以启动 Linux 并运行一个小型 Bash 脚本。该脚本搜索并运行第二个程序(通常是编译后的 C++ 二进制文件)。
您应该能够通过按Ctrl+中止第二个程序C。什么应该发生的情况是第二个程序停止了,Bash 脚本继续运行清理。什么实际上发生的情况是主应用程序和 Bash 脚本都终止。这是一个问题。
所以我使用trap
内置命令告诉 Bash 忽略 SIGINT。现在Ctrl+C终止了 C++ 应用程序,但 Bash 继续运行。伟大的。
哦,是的...有时“第二个应用程序”是另一个 Bash 脚本。并且在那情况下,Ctrl+C现在做什么都没有。
Ctrl显然,我对这个东西如何工作的理解是错误的......当用户按+时,如何控制哪个进程获得 SIGINT C?我想将此信号定向到一个具体过程。
答案1
经过很多很多个小时的互联网搜索,我找到了答案。
这就是为什么编译的二进制文件和启动它的脚本都被破坏了。事实上我只想让主应用程序接收这个信号,不是启动脚本。
现在解决方案很明显:我们需要将应用程序放入一个新的进程组中,并使其成为该 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,并且睡眠模式为前台,那么它无法响应该信号,直到从当前睡眠中唤醒。但如果睡眠模式是后台,它会立即响应。