ssh 通过调用远程 shell 来执行它给出的命令,该脚本由一组完整的本地参数和它们之间的空格连接在一起。
如果你运行:
# This has only syntactic quotes -- none of the quotes are literal.
ssh somehost echo "Hello World"
..那么传递给ssh 的参数列表(在C 语法中,不包括主机名和ssh 命令本身)是{ "echo", "Hello World", NULL }。
连接在一起成为一个字符串,然后变成"echo Hello World"。
因此,远程 shell 运行 echo Hello World,它没有语法引号。
如果你运行:
ssh somehost echo \"Hello World\"
...那么命令列表(同样,在 C 语法中)是 { "echo", "\"Hello", "World\"", NULL }:引号是文字,但是在分词过程中,本地 shell(在运行 SSH 之前)删除了空格。
连接成一个字符串,变成echo "Hello World"。因此,您会得到引号,但会丢失空格。
相比之下,作为一个可行的(但不是特别好的实践)示例,请考虑:
ssh somehost echo \"Hello" "World\"
在这里,您传递了ssh 两个参数:开头和结尾的\"s 对第一个shell 来说是字面意思(没有语法意义,所以Hello 这个词是第一个未引用的shell) ;但是围绕空格的"s 是语法上的,它告诉shell 在调用ssh 时保留该空格(因此引用空格)。因此,您得到{ "echo", "\"Hello World\"", NULL },它连接到字符串echo "Hello World"。
最好的做法是通过只向 ssh 传递一个包含您要运行的整个脚本的字符串来避免这种行为。
# This works
ssh somehost 'echo "Hello World"'
...如果您想以编程方式生成该字符串,您可以这样做(如果您知道您的远程 shell 是 bash——即使 bash-in-/bin/sh 模式是安全的):
remote_command=( echo "Hello World" )
printf -v remote_command_q '%q ' "${remote_command[@]}"
ssh somehost "$remote_command_q"
要使用任何符合 POSIX 的远程 shell 安全地执行此操作,请参阅How to have simple and double quotes in a scripted ssh command 中的 Python 辅助答案