一尘不染

ssh命令引用有什么区别?

linux

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

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

这里对类似问题的回答指出:

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

*我能理解的情况下,但是在此示例中将对局部进行局部评估?同样,--bash命令之前的命令也无济于事。


阅读 233

收藏
2020-06-07

共1个答案

一尘不染

这里要理解的是,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没有任何参数的情况下调用了/tmpin)$1,而是作为参数传递给cd从不取消引用的脚本该变量),但由shssh隐式调用。


如果你知道你的遥控器sh是由bash或ksh的提供-壳配套的$''延伸-你可以做任意argv数组以下(在这种情况下bash-ccd /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能够读取的形式对其进行转义。为了避免这种情况:

# 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"
2020-06-07