为什么使用 -F /dev/stdin 语法时 ssh 会立即断开连接?

ken*_*orb 5 command-line osx ssh process-substitution vagrant

我已经通过以下命令配置并启动了默认的 Ubuntu VM 框:

vagrant init ubuntu/trusty64; vagrant up --provider virtualbox
Run Code Online (Sandbox Code Playgroud)

现在,出于教育目的,我想使用以下语法来 ssh 它:

ssh -F /dev/stdin < <(vagrant ssh-config) default
Run Code Online (Sandbox Code Playgroud)

此命令将成功连接到虚拟机,但它会在打印motd后断开连接。

我想了解为什么会发生这种情况以及是否有办法避免它?

我试过强制伪终端分配没有成功。

我知道以下两个命令语法按预期工作:

vagrant ssh-config > ssh_tmp
ssh -F ssh_tmp default
Run Code Online (Sandbox Code Playgroud)

所以我想知道为什么在使用进程替换语法时会失败?

Gil*_*il' 5

您正在传递命令vagrant ssh-config的标准输入上的输出ssh。到ssh运行远程命令并将远程标准输入连接到本地标准输入时,已到达文件末尾。因此,远程 shell 在其标准输入中看到文件的结尾并立即退出。

通常你应该在不同的文件描述符上传递配置文件:

ssh -F <(vagrant ssh-config) default
Run Code Online (Sandbox Code Playgroud)

但这也不起作用¹因为ssh在读取其配置文件之前关闭非默认文件描述符。因此,您需要将实际文件名传递给ssh进程。如果您不想存储以下输出,它可以是命名管道vagrant ssh-config

mkfifo fifo
vagrant ssh-config >fifo &
ssh -F fifo …
rm fifo
Run Code Online (Sandbox Code Playgroud)

使用zshshell(在 macOS 上默认可用),您可以使用=(...)命令替换的形式,它使用临时文件而不是通过/dev/fd/x以下方式访问的管道:

ssh -F =(vagrant ssh-config) …
Run Code Online (Sandbox Code Playgroud)

¹ 除了在不/dev/fd/x支持的系统上使用命名管道实现进程替换