如果我在 SSH 连接断开之前运行命令,该命令会继续执行吗?
答案1
在大多数情况下,不会。当终端丢失时,进程将收到 SIGHUP。您可以在命令前加上“nohup”以忽略信号。请参阅:
答案2
我将在该帖子中添加另一个有用的建议,这是我几分钟前才学到的:
如果您已经启动了一个需要很长时间的进程(在我的情况下是 tar restore),并且忘记在它前面包含 nohup,您仍然可以防止它在注销时终止。
步骤如下:
- 按Ctrl + Z- 这将暂停该工作
- 进入放弃-h%x, 在哪里X是暂停作业后获得的工作编号
- 执行背景将工作置于后台
- 退出 shell 并继续你的生活:)。
答案3
正如 Warner 上面所说,ssh 守护进程的子进程(即登录 shell 及其子进程)将获得SIGHUP
,但它们不会立即获得。在服务器端的 ssh 守护进程放弃您的连接之前,会有一段延迟,有时需要几分钟。在此期间,该进程将继续运行。
正如华纳所说,该过程可以选择忽略SIGHUP
,在这种情况下,它将继续运行,直到它必须请求输入然后 findSTDIN
关闭。
答案4
我在下面的链接中找到了最好的答案
2016 年编辑:
此问答早于 systemd v230 失败。从 systemd v230 开始,新的默认设置是终止终止登录会话的所有子进程,无论过去采取了哪些有效的预防措施来防止这种情况发生。可以通过在 /etc/systemd/logind.conf 中设置 KillUserProcesses=no 来更改此行为,或者使用 systemd 特定的机制在用户空间中启动守护进程来规避此行为。这些机制超出了本问题的讨论范围。
下面的文字描述了在 Linux 存在的时间更长的 UNIX 设计空间中事物传统的运作方式。
它们会被杀死,但不一定立即被杀死。这取决于 SSH 守护进程需要多长时间才能确定您的连接已断开。接下来是更详细的解释,可以帮助您了解它的实际工作原理。
当您登录时,SSH 守护程序会为您分配一个伪终端,并将其附加到用户配置的登录 shell。这称为控制终端。此时您正常启动的每个程序,无论 shell 层数有多少,最终都会“追溯其祖先”到该 shell。您可以使用 pstree 命令观察这一点。
当与您的连接关联的 SSH 守护进程确定您的连接已断开时,它会向登录 shell 发送挂断信号 (SIGHUP)。这会通知 shell 您已消失,它应该开始自行清理;此时发生的情况是 shell 特有的(在其文档页面中搜索“HUP”),但在大多数情况下,它会在终止之前开始向与其关联的正在运行的作业发送 SIGHUP。这些进程中的每一个,依次在收到该信号后执行它们配置的任何操作。通常这意味着终止。如果这些作业有自己的作业,信号通常也会被传递。
在控制终端挂断后仍能存活下来的进程要么是那些与终端脱离关系的进程(您在其中启动的守护进程),要么是那些使用前缀 nohup 命令调用的进程。(即“不要挂断这个”)
终端多路复用器是保持 shell 环境在断开连接之间完好无损的常用方法。它们允许您以某种方式与 shell 进程分离,以便稍后重新连接到它们,无论断开连接是意外的还是故意的。tmux 和 screen 是比较流行的;使用它们的语法超出了您的问题范围,但它们值得研究。
有人要求我详细说明“SSH 守护程序需要多长时间才能确定您的连接已断开”。这是特定于每个 SSH 守护程序实现的行为,但您可以指望当任何一端重置 TCP 连接时,它们都会终止。如果任何一端尝试写入套接字并且 TCP 数据包未得到确认,则这种情况会很快发生,如果双方都没有尝试写入 PTY,则这种情况会很慢。
在这种特定情况下,最有可能触发写入的因素是:
进程(通常是前台进程)尝试在服务器端(服务器->客户端)写入 PTY。用户尝试在客户端(客户端->服务器)写入 PTY。
任何类型的 Keepalive。通常默认情况下,客户端或服务器都不会启用 Keepalive,并且通常有两种类型:应用程序级别和基于 TCP(即 SO_KEEPALIVE)。Keepalive 相当于服务器或客户端偶尔向另一端发送数据包,即使没有其他理由写入套接字。虽然这通常是为了避开过快超时连接的防火墙,但它还有一个额外的副作用,即当另一端没有更快响应时,发送者会注意到。
TCP 会话的通常规则在此适用:如果客户端和服务器之间的连接中断,但在问题发生期间双方均未尝试发送数据包,则只要双方事后均做出响应并接收到预期的 TCP 序列号,则连接将继续存在。
如果一方认为套接字已死,则通常会立即产生影响:sshd 进程将发送 HUP 并自行终止(如前所述),或者客户端将通知用户检测到的问题。值得注意的是,仅仅因为一方认为另一方已死并不意味着另一方已收到通知,并且通常会保持打开状态,直到它尝试写入连接或收到来自另一方的 TCP 重置。(如果当时连接可用)