我遇到了一个奇怪的问题,Computer A
可以看到Computer B
,Computer B
可以看到Computer C
,但是Computer A
可以不是看Computer C
。
我想制作一个可以在其上运行的 bash 脚本,A
该脚本将调用 上的任意命令C
,但我似乎无法使双引号正常工作。这个想法是:
AMB_CMD='source eniron.dat; cd path/to/code/; make clean all'
ssh -t username@ComputerB "ssh -t username@ComputerC "$AMB_CMD""
我认为解决要运行的内容B
就能解决这个问题,如下所示:
AMB_CMD='source eniron.dat; cd path/to/code/; make clean all'
B_CMD=ssh -t username@ComputerC "$AMB_CMD"
ssh -t username@ComputerB "$B_CMD"
但我仍然遇到问题。
答案1
据我所知,不需要引用实际命令。
ssh username@ComputerB ssh username@ComputerC make clean all
或者,
ssh -J username@ComputerB username@ComputerC make clean all
这将用作ComputerB
连接到 的跳转主机ComputerC
。
使用 OpenSSH 7.3+,配置选项ProxyJump
允许您在以下位置配置跳转主机~/.ssh/config
:
Host ComputerC
User username
ProxyJump username@ComputerB
...所以命令将减少为
ssh ComputerC make clean all
make
根据您的问题的实际组成(问题中没有提到错误消息),它可能与在错误的目录中运行有关。要cd
在运行之前进入正确的目录,make
请使用该实用程序的-C
选项:
ssh username@ComputerC make -C path/to/build/dir clean all
另外,如果您想将实际命令存储在变量中,则不要使用单个字符串,bash
而应使用数组:
cmd=( make -C "path/to/build/dir" clean all )
ssh ... "${cmd[@]}"
答案2
重要的是要意识到传递给的参数ssh
被连接起来组成一个外壳命令行解释为登录外壳远程用户的。
因此,为了能够some-shell-code
通过与 B 的 ssh 连接在 C 上运行,您需要为 B 构建一个命令行,以便 B 用户的登录 shell 正确解释它以将其some-shell-code
按原样传递给ssh
。
如果 A 上的当前 shell、B 上用户的登录 shell 和 C 上用户的登录 shell 都是bash
相同版本(如果某些代码包含非 ASCII 字符,则使用相同的区域设置),并且$CODE
包含bash
要在 C 上执行的代码,您可以执行以下操作:
printf -v quoted_CODE %q "$CODE"
ssh B "ssh C $quoted_CODE"
如果您无法确定 B 或 C 上用户的登录 shell 是bash
,并且不需要通过 stdin 传递任何信息,您可以简单地执行以下操作:
ssh B ssh C bash <<< "$CODE"
或者如果您知道sshd
A 和 B 上允许传入LC_*
变量(AcceptEnv LC_*
常见于sshd_config
):
LC_CODE=$CODE ssh -o SendEnv=LC_CODE B '
ssh -o SendEnv=LC_CODE C bash -c '\'' eval "$LC_CODE"'\'