根据zanco的回答,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
将导致警告Pseudo-terminal will not be allocated because stdin is not a terminal
。还要注意,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
由bash解析,并解释为ssh
命令,后跟user@server
要传递给ssh
命令的参数
"
开始一个内插字符串,完成后将包含要传递给ssh
命令的参数,在这种情况下,该参数将解释ssh
为要执行为的远程命令user@server
$(
开始执行命令,输出由周围的内插字符串捕获
cat
是用于输出后面任何文件的内容的命令。的输出cat
将传递回捕获的内插字符串中
<<
开始bash Heredoc
'EOT'
指定heredoc的名称为EOT。'
EOT周围的单引号指定将Heredoc解析为nowdoc,这是Heredoc的一种特殊形式,其中内容不会被bash插值,而是以文字格式传递
即遇到之间的任何内容<<'EOT'
和<newline>EOT<newline>
将附加到所述nowdoc输出
EOT
终止nowdoc,导致nowdoc临时文件被创建并传递回调用cat
命令。cat
输出nowdoc并将输出传递回捕获的内插字符串
)
总结要执行的命令
"
得出捕获的内插字符串。内插字符串的内容将ssh
作为单个命令行参数传递回,该命令行参数ssh
将解释为以以下方式执行的远程命令: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}"
ssh user@server /bin/bash <<EOT…