【问题标题】:Properly Escape $ in a nested remote command在嵌套的远程命令中正确转义 $
【发布时间】:2016-07-27 18:28:11
【问题描述】:

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

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?

【问题讨论】:

  • 您所有的ssh 命令当前都连接到$HOST1;哪些应该是$HOST2?
  • 您可以/应该告诉 ssh 为您完成使用退回主机的工作。无需自己手动操作。

标签: bash variables ssh


【解决方案1】:

第 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 解析时,它会评估为它的当前内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    • 2020-02-22
    • 2013-03-12
    • 1970-01-01
    相关资源
    最近更新 更多