多年来,我一直使用nohup
或screen
来在通过 SSH 断开与终端的连接后保持进程运行。因此,当我的一个 Linux 或计算机科学新手朋友告诉我ctrl+ D(或exit
)可以做同样的事情,而且可能以更优雅的方式做时,我感到非常震惊。
因此,操作方法如下:首先像往常一样在后台运行您的进程(通过添加&
或使用bg
,无论什么方式),然后,当您想要断开与终端的连接时,使用ctrl+D或exit
注销。
我知道ctrl+D或 是exit
非常常见的退出方式。但是再次登录后,你会发现刚刚启动的进程正在运行......这听起来可能难以置信,我说我很震惊。我在几种不同的情况下尝试了这种方法,包括简单的死循环 python 脚本,它确实有效。
我尝试搜索有关此问题的一些信息,但似乎每个人都在谈论nohup
或screen
。我谈论的方法是常识吗?它只是某些系统或环境的特定功能吗?如果它普遍可用,那么是什么意思nohup
?
答案1
Ctrl+D映射到 ASCII 表中的 EOT。在许多(大多数?)情况下,它被映射到 EOF,这意味着没有更多数据。
对于终端(例如bash
以 tty 的形式运行stdin
),read()
在没有用户输入时调用通常会阻塞,或返回零(没有数据可读取)。当 tty "消失了",bash
最终会读出一个 EOF,表明绝对不会再有输入了。您可以通过输入Ctrl+手动显示 EOF D。
值得注意的是,除非当前行为空,否则bash
诸如此类的用法不会显示 EOF。尝试输入任何内容,然后按+ - 什么也不会发生。readline
CtrlD
当bash
使用脚本作为输入执行时(例如:使用文件作为运行stdin
),一旦读取了最后一个字节,read()
将返回 EOF。此时脚本完成并bash
退出。这与终端的行为相同。
如果您将某个进程置于后台(以 结束命令&
,或使用Ctrl+Z和bg
),那么您将返回到 shell。此时,终止 shell 将对进程产生不同的影响,具体取决于它执行的操作。
- 具有文件的进程
stdin
可能会继续执行,现在由 init(PID 1)继承。 bash
带有来自as 的管道的进程stdin
也将继续执行......直到它尝试调用read()
。此时,read()
将失败,并且应用程序将吸收错误并继续,或者(更可能)因错误而退出。
SIGHUP
(又名 Hang-Up)是向进程发出的信号,用于通知它另一端已“挂断”。我知道这可能是一个晦涩难懂的概念……但在这种情况下,它会通知进程 SSH 客户端已断开连接,或通知子进程bash
已bash
退出,等等……
如果进程没有明确处理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
提前使用。
注意:在这些情况下,写入stdout
或stderr
可能与尝试读取一样致命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
首先,您只能使用nohup
或screen
如果您在运行命令之前知道您需要它在注销之前继续。
当您按下ctrl+时D,输入缓冲区会被发送到正在运行的进程。接下来会发生什么取决于您当前正在使用的应用程序。
在大多数(所有?)终端仿真器和终端中,它只会注销你,结束进程。这意味着如果你有一个进程在后台运行,而这个进程没有被nohup
激活或处于会话中screen
,它会随着你的退出而死亡。
但是,有可能您在某个应用程序中,使用ctrl+D实际上并没有结束它,而是将其置于某种后台状态。
另一个想法是,你的朋友正在考虑ctrl+ z- 这将暂停正在运行的进程,然后你可以使用bg
和将其与正在运行的终端会话“断开连接”。完成此操作后,你可以关闭终端。这基本上与在运行进程之前disown
使用 相同。nohup
然而,一旦该进程被放弃,您就无法“重新附加”该进程。