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

Dmi*_*yas 1 linux ssh bash

我试图通过 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
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

远程操作系统: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;"
Run Code Online (Sandbox Code Playgroud)

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

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

----- ./_b ----
b
----- ./_c ----
c
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*ell 5

需要明确的是,这里有 3 个外壳在工作 - 一个解释 ssh 的外壳,即你的本地外壳;ssh将自动为您运行的那个,并且bash您正在显式调用。

1“消失”的原因是解释ssh命令的shell “吃掉”了-c参数周围的引号,然后另一侧的shellssh在空格处拆分参数。所以它最终看起来像bash -c echo 1 ; echo 2; echo 3. 反过来,-c只是 gets echo,它与一个空行相呼应;1成为那个 shell 的值$1,它没有被使用。然后内部bash返回,直接sshshellecho 2; echo 3正常运行。

考虑一下:

$ ssh xxx bash -c "'echo 1'; echo 2; echo 3"
1
2
3
Run Code Online (Sandbox Code Playgroud)

whereecho 1在 ssh 参数中受到保护,因此传递了第二级 ssh shell bash -c 'echo 1'; echo 2; echo 3。最里面的第 3 级 shell 回显 1,然后第 2 级 ssh shell 回显 2 和 3。

这是另一个有趣的排列:

$ ssh xxx bash -c "'echo 1; echo 2; echo 3'"
1
2
3
Run Code Online (Sandbox Code Playgroud)

在这里,内壳获得所有回声,因为它们被分组在第一个壳内"和第二个壳内'

通常,将参数传递给运行 shell 脚本的 shell 脚本的 shell 脚本可能很难构建。我建议您稍微改变一下技术以节省大量精力。不是将 shell 命令作为命令行参数传递给ssh参数,而是通过标准输入将其提供给 shell。考虑使用这样的管道,避免递归 shell 解释:

$ echo "echo 1; echo 2; echo 3" | ssh -T xxx
1
2
3
Run Code Online (Sandbox Code Playgroud)

(在这里,这-T只是为了抑制 ssh 抱怨缺少伪终端)。