根据zanco的回答,考虑到shell如何解析命令行,您没有向ssh提供远程命令。要解决此问题,请更改ssh命令调用的语法,以便远程命令由语法正确的多行字符串组成。
可以使用多种语法。例如,由于命令可以通过管道传输到bash和sh,也可能是其他shell中,最简单的解决方案是将ssh shell调用与heredocs结合起来:
ssh user@server /bin/bash <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT
注意,在没有/bin/bash的情况下执行上述操作将导致警告伪终端将不会被分配,因为stdin不是终端。还要注意,EOT由单引号包围,这样bash就可以将heredoc识别为nowdoc,关闭局部变量插值,这样命令文本就会原样传递给ssh。
如果你是管道爱好者,你可以将上面的内容重写如下:
cat <<'EOT' | ssh user@server /bin/bash
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT
关于/bin/bash的相同警告也适用于上述情况。
另一种有效的方法是将多行远程命令作为单个字符串传递,使用多层bash变量插值,如下所示:
ssh user@server "$( cat <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT
)"
上述解决方案通过以下方式解决了该问题:
ssh user@server is parsed by bash, and is interpreted to be the ssh command, followed by an argument user@server to be passed to the ssh command
" begins an interpolated string, which when completed, will comprise an argument to be passed to the ssh command, which in this case will be interpreted by ssh to be the remote command to execute as user@server
$( begins a command to be executed, with the output being captured by the surrounding interpolated string
cat is a command to output the contents of whatever file follows. The output of cat will be passed back into the capturing interpolated string
<< begins a bash heredoc
'EOT' specifies that the name of the heredoc is EOT. The single quotes ' surrounding EOT specifies that the heredoc should be parsed as a nowdoc, which is a special form of heredoc in which the contents do not get interpolated by bash, but rather passed on in literal format
Any content that is encountered between <<'EOT' and <newline>EOT<newline> will be appended to the nowdoc output
EOT terminates the nowdoc, resulting in a nowdoc temporary file being created and passed back to the calling cat command. cat outputs the nowdoc and passes the output back to the capturing interpolated string
) concludes the command to be executed
" concludes the capturing interpolated string. The contents of the interpolated string will be passed back to ssh as a single command line argument, which ssh will interpret as the remote command to execute as user@server
如果你需要避免使用像cat这样的外部工具,并且不介意使用两条语句而不是一条,使用内置的read和heredoc来生成SSH命令:
IFS='' read -r -d '' SSH_COMMAND <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT
ssh user@server "${SSH_COMMAND}"