linux - ssh 命令引用有什么区别?

标签 linux bash ssh quotes quoting

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

⋊> 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-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"

上面的警告是,如果你的参数列表可以包含换行符或隐藏字符,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/

相关文章:

linux - 在 linux 中添加系统调用时修改 syscall_table.S

c++ - 如何使用 NetBeans 调试不是用 NetBeans 编译的 C++ 库?

java - 是否有与 package.jsons "bin"等效的 Java/Maven?

node.js - 如何避免在 Jenkins 上出现不需要的 "animated"控制台输出

c++ - C++ 如何解释 system() 的返回值

php - Zend_Db : How to connect to a MySQL database over SSH tunnel?

c++ - C++ 中的 SQLite3 多线程 (linux)

c++ - libssh 不返回命令结果

python - 使用 Paramiko 读取 Top 命令的输出

linux - 为什么我的目标总是被重新编译,即使代码没有任何变化?