为什么在通过ssh传递时,引用空格的命令不起作用?

时间:2017-09-07 11:39:29

标签: bash unix ssh escaping quotes

我正在构建这个项目,我必须使用ssh执行UNIX命令。这是我的问题:当我在UNIX shell中执行以下命令时,

echo "Hello           World"

它产生输出:

Hello           World

中间有5个空格,因为参数在双引号内给出。我想用ssh实现相同的效果。我试图使用反斜杠转义双引号,如下所示:

ssh localhost echo \"Hello           World\"

因为我不希望bash处理引号。但它只是产生

Hello           World

" Hello"之后只有一个空格。 那是为什么?

2 个答案:

答案 0 :(得分:2)

ssh通过调用一个远程shell来执行一个命令,该远程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两个参数:开头和结尾的\"是第一个shell的文字(没有句法意义,所以单词Hello是没有引用的第一个shell);但是只是围绕空格的"是语法的,并告诉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辅助答案

答案 1 :(得分:1)

引号仅出现在客户端上,表示服务器看到:

echo Hello     World

但是此时引号已经丢失,因此空格会崩溃。

您可以在整个命令周围使用单引号:

ssh localhost 'echo "Hello     World"'

现在本地shell不处理字符串,因此内部引号保持不变。

带有转义引号的情况意味着引号在本地shell上无效,因此空格在本地折叠,然后服务器看到:

echo "Hello World"