Bash – Why Process Substitution <() Doesn't Work with ssh -F

bashfile-descriptorsprocess-substitutionsshzsh

I have some vagrant virtual machines. To log into them I issue the vagrant ssh command. I want to log into them using regular ssh command. The vagrant ssh-config outputs the suitable config file

$ vagrant ssh-config
Host default
  HostName 127.0.0.1
  User vagrant
  Port 2201
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /home/cbliard/.vagrant.d/insecure_private_key
  IdentitiesOnly yes
  LogLevel FATAL

When outputing this config in a file and using with ssh -F, everything works fine:

$ vagrant ssh-config > /tmp/config
$ ssh -F /tmp/config default
=> logged successfully

When using process substitution operator <(cmd) to prevent the creation of the temporary config file, it fails:

$ ssh -F <(vagrant ssh-config) default
Can't open user config file /proc/self/fd/11: No such file or directory

Same error happens when using <(cat /tmp/config)

$ ssh -F <(cat /tmp/config) default
Can't open user config file /proc/self/fd/11: No such file or directory

I am using zsh and I observe the same behavior with bash. What am I doing wrong here?

Best Answer

The command:

ssh -F <(vagrant ssh-config) default

runs the vagrant command in a separate process with its stdout connected to a pipe. The other end of the pipe is connected as file descriptor n (in your case it's 11) to a new process that runs ssh and the shell runs:

ssh -F /proc/self/fd/n default

Now, that only works if ssh doesn't close its file descriptors on startup.

Unfortunately, it does.

If using zsh, an alternative is to use the =(...) form of process substitution where instead of using a pipe and /proc/self/fd, it uses a temp file.

Or you could use a file descriptor that ssh doesn't close. For instance, if you're not feeding anything to ssh (if the remote command is not reading anything from stdin) you could use fd 0, e.g.:

vagrant ssh-config | ssh -F /dev/stdin -n default
Related Question