这里要理解的是ssh简单地连接它的参数(与$*相同),并将该连接字符串传递给sh -c.
因此,在以下情况下:
ssh josh-play bash -c 'cd /tmp; pwd'
… ssh运行:
sh -c 'bash -c cd /tmp; pwd'
…因此,sh运行:
bash -c cd /tmp
pwd
…并且你可以测试自己,bash -c cd / tmp并没有做太多有用的事情(它运行的脚本文本只包含cd; / tmp存储为参数,但脚本文本永远不会读取它的参数,这样做没有意义).而且,一旦bash退出,我们就会回到父sh进程,其中cd从未运行过.
传递给你的外壳的语法引号完全丢失,并且pwd不是由你手动触发的bash调用的(在这个用法中,它只是调用没有任何参数的cd – / tmp是$1,但脚本已经通过作为cd的参数永远不会取消引用该变量)但是由ssh隐式调用的sh.
如果你知道你的远程sh是由bash或ksh提供的 – 一个支持$”扩展的shell – 你可以对任意argv数组执行以下操作(在本例中为bash,-c,cd / tmp; pwd) :
# 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"
上面的警告是,如果您的参数列表可以包含换行符或隐藏字符,则bash或ksh中的printf%q可以以不保证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'
# ...and use bash to evaluate that quoted form.
ssh josh-play 'exec bash -s' <<