第 1 部分:字面答案
...对问题的准确提出。
为什么第一个命令给我$x?
请记住,此命令会执行多次,因此会被多个 shell 转换。该转换如下所示(假设 1.1.1.1 的 HOST1 和 2.2.2.2 的 HOST2):
ssh -A 1.1.1.1 -C "x=wrong; ssh -A 2.2.2.2. -C "x=right; echo \$x""
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^
...注意箭头?这些显示了您引用的区域开始和结束的位置:您在 x=right 之前的报价正在结束您在 x=wrong 之前开始的报价!
因此,这将标记为两个单独的命令,每行用一个 shell 字写出:
# command one: ssh
ssh \
-A \
1.1.1.1 \
-C \
"x=wrong; ssh -A 2.2.2.2. -C "x=right;
# command two: echo
echo \
\$x""
保留双引号,如何打印right?
反斜杠转义嵌套的引号,这样它们就不会关闭您打算放在外部的引号。
ssh -A $HOST1 -C "x=wrong; ssh -A $HOST2 -C \"x=right; echo \$x\""
第 2 部分:最佳实践替代方案
SSH - 代理命令
实际上,根本不要进行这种显式嵌套的 SSH 调用——只需使用 ProxyCommand ssh 配置选项:
ssh \
-o "ProxyCommand ssh $HOST1 netcat -w 120 %h %p' \
"$HOST2" 'x=right; echo "$x"'
Bash - 可嵌套的评估安全报价生成
一般来说,尝试手动逃避事情比告诉 shell 为你做这件事更容易出错。
host2_cmd='x=right; echo "$x"'
printf -v host1_cmd '%q ' ssh -A "$HOST2" -C "$host2_cmd"
ssh "$HOST1" bash -s <<<"$host1_cmd"
为了演示,我们甚至可以通过第三个主机来做到这一点:
host3_cmd='x=right; echo "$x"'
printf -v host2_cmd '%q ' ssh -A "$HOST3" -C "$host3_cmd"
printf -v host1_cmd '%q ' ssh -A "$HOST2" -C "$host2_cmd"
ssh "$HOST1" bash -s <<<"$host1_cmd"
这是可行的,因为在 ksh 和 bash 中,printf %q 以这样一种方式引用一个字符串,当它被同一个 shell 解析时,它会评估为它的当前内容。