早在我年轻的时候,Unix就是新事物,创建一个在你退出时不被杀的过程是一个挑战。我们使用nohup命令来保护我们的持久进程免受HUP
信号的影响。如果我们不小心,我们的进程会在我们注销时被杀死,甚至关闭我们启动它们的shell。
快进到今天,我发现我很惊讶默认情况恰恰相反。在Ubuntu和Red Hat系统上,我发现我几乎可以在后台放置任何进程,杀死父shell,注销,任何事情都会继续。我看到了与Bash脚本,Python脚本和C程序相同的行为。我从xterm或ssh会话中得到了相同的行为。
例如,在xterm或ssh窗口中,键入:
while [ 1 ]; do date; sleep 10; done > /tmp/out &
现在从另一个窗口运行
tail -f /tmp/out
观察它每10秒打印一次日期,然后用Ctrl-D关闭原始父shell。仍在运行。退出并重新登录。仍在运行。
发送HUP
信号,它会立即死亡。
我可以使用Python脚本或C程序表现出相同的行为。睡不与无关。例如,这个丑陋的C程序表现相同:
#include <stdio.h>
void main() {
while(1) {
printf("*\n");
fflush(stdout);
int i, j, k = 0;
for(i=0; i < 10000; i++) {
for(j=0; j < 100000; j++) {
k += i * j;
}
}
}
}
这完全违背了我年轻时的方式。我想我刚才没注意到它改变了吗?那里的历史学家都知道这发生的时间? HUP
是否甚至被用于此目的?
如果这确实是现状,我的问题是:如何在用户注销或断开连接时安排流程死亡?
我有一个黑客,需要注意ppid
(父母的pid)改变,但肯定会有更优雅的东西。
答案 0 :(得分:5)
我相信你正在寻找huponexit
shell选项。您可以使用
$ shopt -s huponexit
bash手册页中的一些细节:
shell收到SIGHUP后默认退出。之前 退出时,交互式shell会将SIGHUP重新发送到所有正在运行的作业 要么 停止。停止的作业被发送SIGCONT以确保他们收到SIGHUP。防止shell发送信号 一个 应该从作业表中删除它与内置的disown(参见下面的SHELL BUILTIN命令)或标记为不 接收 SIGHUP使用disown -h。
如果已使用shopt设置了huponexit shell选项,则当交互式登录shell退出时,bash会向所有作业发送一个SIGHUP。
答案 1 :(得分:4)
我仍然得到一个大声。一种简单的测试方法:
#!/usr/bin/env sh
echo "$$"
trap "echo HUPPED $$ > /tmp/willithup" HUP
sleep 1000
然后关闭终端仿真器。现在回到你的问题:
观察它每10秒打印一次日期,然后关闭原稿 使用Ctrl-D的父shell。仍在运行。退出并重新登录。仍然 运行
当父进程死亡时,该进程不会获得HUP。当它失去与控制终端的连接或者显式发送HUP时,它获得HUP。例如,当您注销SSH时会发生这种情况。
如果我们不小心,我们的进程会在我们记录时被杀死 关闭,甚至关闭我们从
开始的shell
对于第二个:shell本身可以在其退出时向其所有子节点发送HUP。但是,bash例如默认情况下huponexit
设置为false。这很可能是变化的。请注意,无论huponexit选项如何,在收到HUP时,shell也会向其所有子项发送HUP 。
用史蒂文斯的话来说:
会话可以有一个控制终端。这通常是 终端设备(在终端登录的情况下)或伪终端 我们登录的设备(在网络登录的情况下)。
如果终端检测到调制解调器(或网络)断开连接 接口挂断信号被发送到控制过程( 会议负责人)。
为了进一步说明,shell不会发送初始HUP 。它由终端驱动程序发送。之后,贝壳将“转发”给孩子们。实际上,终端驱动程序发送的HUP可以“级联”。来自TLPI:
当控制进程失去其终端连接时,内核 发送一个SIGHUP信号告知它这个事实。 (SIGCONT信号 也会发送,以确保重新启动进程,以防万一 先前已被信号拦截。)通常,这可能发生在两个 情况:
- 当终端驱动程序检测到“断开连接”时,表示调制解调器或终端线路上的信号丢失。
- 在工作站上关闭终端窗口时。发生这种情况是因为与终端窗口关联的伪终端主端的最后一个打开文件描述符已关闭。