为什么 SSH -t 不等待后台进程?

Phi*_*rry 14 shell process ssh file-descriptors background-process

为什么ssh -t不等待后台作业完成?

例子:

ssh user@example 'sleep 2 &'
Run Code Online (Sandbox Code Playgroud)

这按预期工作,因为 ssh 在 2 秒后返回,而

ssh user@example -t 'sleep 2 &'
Run Code Online (Sandbox Code Playgroud)

不等待sleep完成并立即返回。

任何人都可以解释这背后的原因吗?有没有办法ssh -t在返回之前等待所有后台进程完成?

我的用例是我用 启动一个脚本ssh -t,这个脚本启动几个后台作业,这些作业在主脚本完成后应该保持活动状态。随着ssh -t这是不可能的为止。

Sté*_*las 24

如果没有-t,sshdsleep通过两个管道获取远程 shell(以及类似)和 stderr 的标准输出(并且还通过另一个管道发送客户端的输入)。

sshd 确实等待它启动用户登录 shell 的进程,而且在该进程终止后等待 stdout 管道上的 eof(至少在 openssh 的情况下不是 stderr 管道)。

当管道写入端的任何进程没有打开文件描述符时,就会发生 eof,这通常只发生在所有没有将其 stdout 重定向到其他内容的进程都消失时。

使用时-tsshd不使用管道。相反,与远程 shell 及其子级的所有交互(stdin、stdout、stderr)都是使用一对伪终端完成的。

使用伪终端对,为了sshd与主端交互,没有类似的 eof 处理,而至少某些系统提供了替代方法来了解是否仍有对伪终端的从端打开 fds 的进程(参见 @ JdeBP 注释如下),sshd不使用它们,所以它只是等待它执行远程用户的登录 shell 的进程的终止,然后退出。

在退出时,pty 对的主端关闭,这意味着 pty 被销毁,因此由从属控制的进程将收到 SIGHUP(默认情况下会终止它们)。

编辑:最后一部分不正确,但最终结果是相同的。请参阅@pynexj 的回答以正确描述究竟发生了什么。