所有相关信息都在现有的答案中,但让我尝试一个实用的总结:
tl; diana:
使用命令行参数传递命令:
SSH jdoe@server“…”
“…'字符串可以跨越多行,所以即使不使用here-document,你也可以保持代码的可读性:
SSH jdoe@server“…”
不要通过stdin传递命令,就像你使用here-document一样:
ssh jdoe@server <<'EOF' #不这样做…EOF
将命令作为参数传递,按原样工作,并且:
伪终端的问题甚至不会出现。
您不需要在命令末尾使用退出语句,因为会话将在处理完命令后自动退出。
简而言之:通过stdin传递命令是一种与ssh的设计不一致的机制,并且会导致必须解决的问题。
如果你想了解更多,请继续阅读。
可选背景信息:
Ssh接受在目标服务器上执行的命令的机制是一个命令行参数:最后一个操作数(非选项参数)接受一个包含一个或多个shell命令的字符串。
By default, these commands run unattended, in a non-interactive shell, without the use of a (pseudo) terminal (option -T is implied), and the session automatically ends when the last command finishes processing.
In the event that your commands require user interaction, such as responding to an interactive prompt, you can explicitly request the creation of a pty (pseudo-tty), a pseudo terminal, that enables interacting with the remote session, using the -t option; e.g.:
ssh -t jdoe@server 'read -p "Enter something: "; echo "Entered: [$REPLY]"'
Note that the interactive read prompt only works correctly with a pty, so the -t option is needed.
Using a pty has a notable side effect: stdout and stderr are combined and both reported via stdout; in other words: you lose the distinction between regular and error output; e.g.:
ssh jdoe@server 'echo out; echo err >&2' # OK - stdout and stderr separate
ssh -t jdoe@server 'echo out; echo err >&2' # !! stdout + stderr -> stdout
如果没有这个参数,ssh会创建一个交互式shell——包括当你通过stdin发送命令时,这就是问题开始的地方:
For an interactive shell, ssh normally allocates a pty (pseudo-terminal) by default, except if its stdin is not connected to a (real) terminal.
Sending commands via stdin means that ssh's stdin is no longer connected to a terminal, so no pty is created, and ssh warns you accordingly:
Pseudo-terminal will not be allocated because stdin is not a terminal.
Even the -t option, whose express purpose is to request creation of a pty, is not enough in this case: you'll get the same warning.
Somewhat curiously, you must then double the -t option to force creation of a pty: ssh -t -t ... or ssh -tt ... shows that you really, really mean it.
Perhaps the rationale for requiring this very deliberate step is that things may not work as expected. For instance, on macOS 10.12, the apparent equivalent of the above command, providing the commands via stdin and using -tt, does not work properly; the session gets stuck after responding to the read prompt:
ssh -tt jdoe@server <<<'read -p "Enter something: "; echo "Entered: [$REPLY]"'
在不太可能发生的情况下,您想要作为参数传递的命令使命令行对您的系统来说太长(如果它的长度接近getconf ARG_MAX -请参阅本文),请考虑先以脚本的形式将代码复制到远程系统(例如,使用scp),然后发送命令来执行该脚本。
在紧急情况下,使用-T,并通过stdin提供命令,后面有一个退出命令,但请注意,如果您还需要交互功能,则使用-tt代替-T可能不起作用。