在嵌套的远程命令中正确转义$

时间:2016-07-27 18:28:11

标签: bash variables ssh

我想从另一台远程主机上执行远程主机上的命令。

HOST1=host1.domain.tld
HOST2=host2.domain.tld

HOST1用于连接HOST2,命令在HOST2上执行。远程命令取决于在HOST2上计算的变量。

ssh -A $HOST1 -C "x=wrong; ssh -A $HOST2 -C "x=right; echo \$x""

奇怪的是,上面的命令返回$x而下一个命令返回wrong而不是空行。

ssh -A $HOST1 -C "x=wrong; ssh -A $HOST2 -C "echo \$x""

问题1:为什么第一个命令给我$x
问题2:保留双引号,如何打印right

1 个答案:

答案 0 :(得分:0)

第1节:文字答案

...正是提出的问题。

为什么第一个命令给我$x

请记住,此命令会多次执行,因此会被多个shell转换。该转换看起来类似于以下(假设{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 - ProxyCommand

在实践中,根本不要进行这种明确的嵌套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解析时评估其当前内容。