当我想将本地文件与远程文件进行比较时,以下任何一个通常都可以工作:
$ ssh remote cat file | diff file -
$ diff file <(ssh remote cat file)
但是,有时(特别是需要密码时)它们会失败,如下所示:
$ ssh remote cat file | diff file -
1,162d0
< ...
< ...
Password:
这里,diff
不等待ssh
完成并认为第二个文件为空。直到diff
完成后才ssh
要求输入密码,但为时已晚。
$ diff file <(ssh remote cat file)
Password:
Password: # asking again after a few seconds
#&%Pasword: # the typed raw password leaks into the terminal
user@remote's password:
Permission denied, please try again.
user@remote's password:
Permission denied, please try again.
user@remote's password:
Received disconnect from XXX.XX.XX.XX: 2: Too many authentication failures for user
1,162d0
< ...
< ...
这次,ssh
要求输入密码,但输入的密码会回显到终端,但ssh
无法获取。最后,ssh
失败并diff
继续使用空的第二个文件。
您能否解释一下为什么会发生这些情况,或者详细说明发生了什么在引擎盖下?
答案1
当您首先运行 ssh 时:
ssh remote 'cat file' | cat
ssh 将您的控制终端作为标准输入,因此您可以毫无问题地输入密码。
当你使用 bash 时流程替代,stdin 保持连接到第一个命令,并且子进程的输出管道作为参数传递给第一个命令:
cat <(ssh remote 'cat file')
如果 ssh 协商成功,/dev/fd/63
将是一个包含 输出的管道ssh remote 'cat file'
。
这可以通过以下命令进行演示:
$ echo <(ls)
/dev/fd/63
其中重要的部分是您的终端连接到 的cat
stdin,而不是ssh
的。当它运行时,cat
会得到一个命令行参数,例如/dev/fd/63
.因此,cat 完全忽略 stdin;但是,它仍然连接到 cat 进程,而不是ssh
,因此您的密码无处可去。
如果您想更改此设置,则需要ssh
先运行,并将输出通过管道传输到diff
,如上面所示:
ssh remote 'cat file' | diff file -