断开与终端的连接后,在 Linux 中保持进程继续运行,使用 ctrl+D 解决方案?

断开与终端的连接后,在 Linux 中保持进程继续运行,使用 ctrl+D 解决方案?

多年来,我一直使用nohupscreen来在通过 SSH 断开与终端的连接后保持进程运行。因此,当我的一个 Linux 或计算机科学新手朋友告诉我ctrl+ D(或exit)可以做同样的事情,而且可能以更优雅的方式做时,我感到非常震惊。

因此,操作方法如下:首先像往常一样在后台运行您的进程(通过添加&或使用bg,无论什么方式),然后,当您想要断开与终端的连接时,使用ctrl+Dexit注销。

我知道ctrl+D或 是exit非常常见的退出方式。但是再次登录后,你会发现刚刚启动的进程正在运行......这听起来可能难以置信,我说我很震惊。我在几种不同的情况下尝试了这种方法,包括简单的死循环 python 脚本,它确实有效。

我尝试搜索有关此问题的一些信息,但似乎每个人都在谈论nohupscreen。我谈论的方法是常识吗?它只是某些系统或环境的特定功能吗?如果它普遍可用,那么是什么意思nohup

答案1

Ctrl+D映射到 ASCII 表中的 EOT。在许多(大多数?)情况下,它被映射到 EOF,这意味着没有更多数据。

对于终端(例如bash以 tty 的形式运行stdin),read()在没有用户输入时调用通常会阻塞,或返回零(没有数据可读取)。当 tty "消失了",bash最终会读出一个 EOF,表明绝对不会再有输入了。您可以通过输入Ctrl+手动显示 EOF D

值得注意的是,除非当前行为空,否则bash诸如此类的用法不会显示 EOF。尝试输入任何内容,然后按+ - 什么也不会发生。readlineCtrlD

bash使用脚本作为输入执行时(例如:使用文件作为运行stdin),一旦读取了最后一个字节,read()将返回 EOF。此时脚本完成并bash退出。这与终端的行为相同。

如果您将某个进程置于后台(以 结束命令&,或使用Ctrl+Zbg),那么您将返回到 shell。此时,终止 shell 将对进程产生不同的影响,具体取决于它执行的操作。

  • 具有文件的进程stdin可能会继续执行,现在由 init(PID 1)继承。
  • bash带有来自as 的管道的进程stdin也将继续执行......直到它尝试调用read()。此时,read()将失败,并且应用程序将吸收错误并继续,或者(更可能)因错误而退出。

SIGHUP(又名 Hang-Up)是向进程发出的信号,用于通知它另一端已“挂断”。我知道这可能是一个晦涩难懂的概念……但在这种情况下,它会通知进程 SSH 客户端已断开连接,或通知子进程bashbash退出,等等……

如果进程没有明确处理SIGHUP,则默认操作是终止它。因此询问bash 向它的一个子进程发送一个消息SIGHUP将允许它在 shell 消失后有效地运行。


如果你想让命令在后台运行而不先做基础工作(查看tmux作为 的更好版本screen),那么你需要明确说明“我不想再将此进程附加到此 shell“。

为了实现此目的,您可以使用disown参考这里,但您需要搜索/滚动),它将为您整理一切,并让进程继续运行:

放弃 [-ar] [-h] [jobspec ...]

如果没有选项,则每个 jobspec 都会从活动作业表中删除。如果没有 jobspec,并且没有提供 -a 或 -r,则使用 shell 的当前作业概念。如果给出了 -h 选项,则不会从表中删除每个 jobspec,但会对其进行标记,以便 shell 收到 SIGHUP 时不会向该作业发送 SIGHUP。如果没有 jobspec,并且没有提供 -a 或 -r 选项,则使用当前作业。如果没有提供 jobspec,则 -a 选项表示删除或标记所有作业;没有 jobspec 参数的 -r 选项将操作限制为正在运行的作业。除非 jobspec 未指定有效作业,否则返回值为 0。

read()如果该进程尝试断开连接,事情仍可能会出错stdin,因此如果您明确想要断开正在运行的进程,则请确保stdin指向/dev/null或类似,或者tmux提前使用。


注意:在这些情况下,写入stdoutstderr可能与尝试读取一样致命stdin...SIGPIPE 啊嘿。


借助工具重定向stdin正在stdout运行stderr的进程,通过使用调试系统调用,可以更安全地退出进程(您可能会遇到困难,请参阅)。我努力想起来以前用过的 C 应用程序的名称,但翻找了一下,发现dupx这也可能会有帮助,或者至少值得研究一下。

两者的运作方式基本上都是在目标进程中执行以下操作:

fd = open("/dev/null", O_RDONLY);
dup2(fd, stdin);
close(fd);

fd = open("/dev/null", O_WRONLY);
dup2(fd, stdout);
dup2(fd, stderr);
close(fd);

答案2

首先,您只能使用nohupscreen如果您在运行命令之前知道您需要它在注销之前继续。

当您按下ctrl+时D,输入缓冲区会被发送到正在运行的进程。接下来会发生什么取决于您当前正在使用的应用程序。

在大多数(所有?)终端仿真器和终端中,它只会注销你,结束进程。这意味着如果你有一个进程在后台运行,而这个进程没有被nohup激活或处于会话中screen,它随着你的退出而死亡。

但是,有可能您在某个应用程序中,使用ctrl+D实际上并没有结束它,而是将其置于某种后台状态。

另一个想法是,你的朋友正在考虑ctrl+ z- 这将暂停正在运行的进程,然后你可以使用bg和将其与正在运行的终端会话“断开连接”。完成此操作后,你可以关闭终端。这基本上与在运行进程之前disown使用 相同。nohup

然而,一旦该进程被放弃,您就无法“重新附加”该进程。

相关内容