ssh命令引用有什么区别?

时间:2017-03-01 16:39:38

标签: linux bash ssh quotes quoting

这些命令如何导致不同的输出?

⋊> ssh host bash -c 'cd /tmp; pwd'
/home/manu
⋊> ssh host "bash -c 'cd /tmp; pwd'"
/tmp

对类似问题here的回答指出:

  

尾随参数组合成一个字符串,该字符串作为参数传递给远程计算机上登录shell的-c选项。

如果是*,我可以理解这一点,但在这个例子中,本地评估的部分是什么?此外,bash命令之前的--没有帮助。

1 个答案:

答案 0 :(得分:6)

这里要理解的是ssh只是简单地连接它的参数(与$*一样),并将该连接的字符串传递给sh -c

因此,在以下情况下:

ssh josh-play bash -c 'cd /tmp; pwd'

... ssh运行:

sh -c 'bash -c cd /tmp; pwd'

...因此,sh run:

bash -c cd /tmp
pwd

...正如您可以自己测试一样,bash -c cd /tmp并没有做太多有用的事情(它运行的脚本文本只包含cd; {{1}存储为一个参数,但脚本文本永远不会读取它的参数,这样就没有了。此外,只要/tmp退出,我们就会回到父bash进程中,sh从未运行过。

传递给外壳的语法引号完全丢失,cd不是由您手动触发的pwd调用的(在此用法中,只调用bash没有任何参数 - cd/tmp中,但作为参数传递给$1的脚本从不取消引用该变量),而是由ssh隐式调用的cd。 / p>

如果您知道您的远程sh由bash或ksh提供 - 一个支持sh扩展名的shell - 您可以对任意argv数组执行以下操作(在本例中为{{ 1}},$''bash):

-c

上面的警告是,如果您的参数列表可以包含换行符或隐藏字符,bash或ksh中的cd /tmp; pwd可以以POSIX sh无法读取的形式转义它。为了避免这种情况:

# ask your shell to generate an eval-safe quoted form of your argument list
printf -v rmt_cmd '%q ' bash -c 'cd /tmp; pwd'

# pass that through to be run by the remote sh -c
ssh josh-play "$rmt_cmd"