远程ssh命令:第一个回波输出丢失

时间:2018-11-07 20:38:01

标签: linux bash ssh

我试图通过ssh 1-liner调用在远程框中运行多个命令,方法是将它们指定为以分号分隔的字符串(传递给“ bash -c”)。它适用于某些情况,但不适用于其他情况。检查一下:

# Note: the "echo 1" output is lost:
bash-3.2$ ssh sandbox bash -c "echo 1; echo 2; echo 3"

2
3

# Note: first echo is ignored again
bash-3.2$ ssh sandbox bash -c "echo 0; echo 1; echo 2; echo 3"

1
2
3

# But when we run other commands (for example "date") then nothing is lost
bash-3.2$ ssh sandbox bash -c "date; date;"
Wed Nov  7 20:27:55 UTC 3018
Wed Nov  7 20:27:55 UTC 3018

我想念什么?

远程操作系统:Ubuntu 16.04.5 LTS
远程ssh:OpenSSH_7.2p2 Ubuntu-4ubuntu2.4,OpenSSL 1.0.2g 2016年3月1日

本地操作系统:macOS High Sierra Versoin 10.13.3
本地ssh:OpenSSH_7.6p1,LibreSSL 2.6.2

更新: 上面的示例是我正在尝试做的简化的图片。 实际的应用实际上是通过回显到远程文件系统来在远程盒上生成少量文件:

#!/bin/bash

A=a
B=b
C=c

ssh -i ~/.ssh/${REMOTE_FQDN}.pem ${REMOTE_FQDN} sudo bash -c \
  "echo $A > /tmp/_a; echo $B > /tmp/_b; echo $C > /tmp/_c;"

运行上述脚本并转到远程框检查结果后,我看到以下内容:

root@sandbox:/tmp# for i in `find ./ -name '_*'|sort`; do echo "----- ${i} ----"; cat $i; done
----- ./_a ----

----- ./_b ----
b
----- ./_c ----
c

如您所见,第一个“ echo”命令生成了空白文件!

2 个答案:

答案 0 :(得分:4)

要清楚的是,这里有3个shell在起作用-一个解释ssh的shell,即本地shell。 ssh将自动为您运行,而您正在显式调用bash

“ 1”消失的原因是解释ssh命令的外壳“吃掉了-c参数周围的引号,然后是 other上的外壳ssh的em>边在空白处分割参数。因此最终看起来像bash -c echo 1 ; echo 2; echo 3。反过来,-c仅得到echo,它会回显一个空行。 1成为该shell的$1的值,未使用。然后内部的bash返回,并且直接的ssh shell正常运行echo 2; echo 3

考虑一下:

$ ssh xxx bash -c "'echo 1'; echo 2; echo 3"
1
2
3

其中echo 1受ssh参数保护,因此第二级ssh shell被传递bash -c 'echo 1'; echo 2; echo 3。最里面的3层外壳回显1,然后2层ssh外壳回显2和3。

这是另一个有趣的排列:

$ ssh xxx bash -c "'echo 1; echo 2; echo 3'"
1
2
3

在这里,内层外壳将获得所有回声,因为它们在第一个外壳内按"分组,在第二个外壳内按'分组。

通常,很难将要传递参数到运行Shell脚本的Shell脚本的Shell脚本构建。我建议您稍微改变一下技巧以节省很多精力。您可能会考虑使用管道,这样可以避免递归shell解释:

$ echo "echo 1; echo 2; echo 3" | ssh -T xxx
1
2
3

(这里的-T只是为了阻止ssh抱怨缺少伪终端)。

答案 1 :(得分:2)

ssh的所有参数都组合成一个单独的空格字符串,该字符串传递到远端的sh -c。这意味着

ssh sandbox bash -c "echo 1; echo 2; echo 3"

执行

sh -c 'bash -c echo 1; echo 2; echo 3'

请注意引号的丢失;删除引号后,ssh得到了三个参数bash-cecho 1; echo 2; echo 3。在远端,bash -c echo 1仅执行echo,而外壳程序中的$0设置为1。

命令

ssh sandbox bash -c "date; date;"

的处理方式相同,但是现在第一个命令不包含空格。远端的结果是

sh -c 'bash -c date; date;'

这意味着首先是bash的新实例运行date命令,然后是date直接执行的sh命令。

通常,使用ssh的隐式串联是一个坏主意。始终将要执行的命令作为正确转义的 single 参数传递:

ssh sandbox 'bash -c "echo 1; echo 2; echo 3"'