nohup 和 disown 都可以在退出 shell 后仍然让程序运行吗

nohup 和 disown 都可以在退出 shell 后仍然让程序运行吗

我正在发现nohupUbuntudisownbash.

我有while.py

import time
while True:
    print(1)
    time.sleep(1)

首先,我使用 ssh 连接到我的 ubuntu 服务器并输入nohup python3 while.py &.然后我进入exit退出终端。重新连接服务器并输入后ps aux | grep python,我可以清楚地看到进程正在运行。然后我杀掉这个进程。

第二,我进入了python3 while.py & disown。程序开始1在 shell 中打印。然后我退出 shell 并重新连接到服务器。但是,当我输入 时ps aux | grep python,我看不到进程正在运行。

似乎否认并没有阻止进程在关闭终端后被终止。我已经搜索过相关问题。塞尔奇克提到disown确保 shell 不会向它发送 SIGHUP 并且nohup确保进程不会收到任何发送的 SIGHUP。这个答案提到终端在关闭时向所有进程发送 SIGHUP、SIGCONT、SIGCHID。因此我有一个问题,为什么 nohup 和 disown 在关闭终端后表现不同。

英语不是我的母语。如果存在语法错误,请原谅。如果您能提供帮助,我将不胜感激。

答案1

在unix最初的硬件环境中,“终端”是一个连接到串行端口的硬件。这可以是实际的终端或电话线上的调制解调器或类似的东西。

如果您使用远程调制解调器呼叫调制解调器并连接,则您将登录到系统。当您断开连接(“挂断”)时,系统会向连接到串行端口的所有设备发送 HUP。然后,系统会将 HUP 信号(请参阅 参考资料man -s 7 signal)发送到连接到该串行端口的每个进程,以清除它们并使该端口可供下一个用户使用。如果您退出物理终端,这也会模拟挂断。

串行端口仍然存在,但大多数“终端”现在都是虚拟的,以软件实现,并通过伪终端 (pty) 接口进行连接。但这仍然与串行端口几乎相同。伪终端有两个接口:一个是终端软件连接的主接口,另一个是客户端,其作用类似于外部串行端口的软件端。

当主 pty 关闭(可能通过关闭窗口或断开 ssh 连接)或发生任何数量的其他操作时,这会触发调制解调器挂断会触发的相同事件,向连接到终端的每个进程发送 HUP 信号。

nohup命令阻止进程接收 HUP 信号,因此它不会被直接杀死。但是,它可能仍然有连接到终端的标准输入和标准输出。 master pty 关闭后,stdin 和 stdout 将被有效地替换为 /dev/null,这可能会导致进程在尝试读取时在 stdin 上收到 EOF,这仍然可能导致其退出。

如果 shell 有后台作业并且您退出 shell,它通常会尝试使用 HUP 信号杀死它所知道的作业,以在其自身之后进行清理。该disown命令告诉 shell 忘记其作业控制列表中的作业。但这并不会解除作业中的进程与终端的关联,终端可能仍会尝试摆脱它们。

答案2

我已经发现问题的原因了。这个答案提到

如果终端是被摧毁(如果它是一个 pty,就像 xterm 或 ssh 创建的 pty,并且通过关闭 xterm 或终止 SSH 连接来终止控制程序,则可能会发生这种情况),程序将失败一旦它尝试从标准输入读取或者写入标准输出

终端退出后, disown 不会断开与stdout或 的连接stderr。我的程序print(1),它尝试写入stdout并导致程序崩溃。

为了解决这个问题,我们只需要重定向stdoutstderr通过python3 while.py >/dev/null 2>&1 & disown

答案3

disown 会从 shell 的作业控制中删除该进程,该进程仍将附加到终端会话 - 因此,当您退出终端时,该进程将会终止。

相关内容