这些命令如何导致不同的输出?
⋊> ssh host bash -c 'cd /tmp; pwd'
/home/manu
⋊> ssh host "bash -c 'cd /tmp; pwd'"
/tmp
类似问题的答案 here指出:
The trailing arguments are combined into a single string which is passed to as an argument to the -c option of your login shell on the remote machine.
在 *
的情况下,我可以理解这一点,但是在这个例子中,哪些部分会在本地进行评估?此外,bash 命令前的 --
也无济于事。
最佳答案
这里要理解的是 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' <<<"$rmt_cmd"
关于linux - ssh 命令引用有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42537239/