这些命令如何导致不同的输出?
⋊> ssh host bash -c 'cd /tmp; pwd' /home/manu ⋊> ssh host "bash -c 'cd /tmp; pwd'" /tmp
这里对类似问题的回答指出:
尾随参数组合为一个字符串,该字符串作为参数传递给远程计算机上登录shell的-c选项。
在*我能理解的情况下,但是在此示例中将对局部进行局部评估?同样,--bash命令之前的命令也无济于事。
*
--
这里要理解的是,ssh只需将其参数串联起来(以相同的方式$*),然后将串联的字符串传递给sh -c。
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从未运行过。
bash -c cd /tmp
cd
/tmp
bash
sh
传递给外壳程序的句法引号完全丢失,并且pwd不是由bash您手动触发的调用(在此用法中,该调用只是在cd没有任何参数的情况下调用了/tmpin)$1,而是作为参数传递给cd从不取消引用的脚本该变量),但由shssh隐式调用。
pwd
$1
如果你知道你的遥控器sh是由bash或ksh的提供-壳配套的$''延伸-你可以做任意argv数组以下(在这种情况下bash,-c,cd /tmp; pwd):
$''
-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"
上面的警告是,如果您的参数列表可以包含换行符或隐藏的字符,则printf %qbash或ksh可以以不能保证POSIX sh能够读取的形式对其进行转义。为了避免这种情况:
printf %q
# 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' <<<"$rmt_cmd"