Sud*_*ura 3 unix ssh bash quotes escaping
我正在构建这个项目,其中我必须使用 ssh 执行 UNIX 命令。这是我的问题:当我在 UNIX shell 中执行以下命令时,
echo "Hello World"
Run Code Online (Sandbox Code Playgroud)
它产生输出:
echo "Hello World"
Run Code Online (Sandbox Code Playgroud)
中间有 5 个空格,因为参数是在双引号内给出的。我也想用 ssh 达到同样的效果。我试图使用反斜杠转义双引号,如下所示:
ssh localhost echo \"Hello World\"
Run Code Online (Sandbox Code Playgroud)
因为我不想让 bash 处理引号。但它只是产生
Hello World
Run Code Online (Sandbox Code Playgroud)
“Hello”后面只有一个空格,这是为什么?
ssh执行通过调用远程 shell 给出的命令,其中脚本由完整的本地参数集组成,参数之间用空格连接在一起。
如果你运行:
# This has only syntactic quotes -- none of the quotes are literal.
ssh somehost echo "Hello World"
Run Code Online (Sandbox Code Playgroud)
..那么传递给的参数列表ssh(在 C 语法中,不包括主机名和 ssh 命令本身)是{ "echo", "Hello World", NULL }。
连接在一起形成一个字符串,然后就变成了"echo Hello World"。
因此,远程 shell 运行echo Hello World,它没有语法引号。
如果你运行:
ssh somehost echo \"Hello World\"
Run Code Online (Sandbox Code Playgroud)
...然后命令列表(同样是 C 语法)是{ "echo", "\"Hello", "World\"", NULL }: 引号是文字,但空格在分词过程中被本地 shell(在运行 SSH 之前)删除。
连接成字符串,就变成了echo "Hello World"。因此,您得到了引号,但失去了空格。
相比之下,作为一个有效(但不是特别最佳实践)的示例,请考虑:
ssh somehost echo \"Hello" "World\"
Run Code Online (Sandbox Code Playgroud)
在这里,您传递ssh两个参数:\"开头和结尾的 s 对于第一个 shell 来说是字面意思(没有语法意义,因此该单词Hello对于第一个 shell 而言不带引号);但是"围绕空格的 s 是语法上的,它告诉 shell 在调用时保留该空格(因此空格被引用)ssh。因此,您得到{ "echo", "\"Hello World\"", NULL },它连接到字符串echo "Hello World"。
最佳实践是通过仅将包含要运行的整个脚本的单个字符串传递到 ssh 来避免此行为。
# This works
ssh somehost 'echo "Hello World"'
Run Code Online (Sandbox Code Playgroud)
...如果您想以编程方式生成该字符串,您可以这样做(如果您知道您的远程 shell 是 bash - 即使 bash-in-/bin/sh模式也是安全的):
remote_command=( echo "Hello World" )
printf -v remote_command_q '%q ' "${remote_command[@]}"
ssh somehost "$remote_command_q"
Run Code Online (Sandbox Code Playgroud)
要使用任何符合 POSIX 标准的远程 shell 安全地执行此操作,请参阅如何在脚本化 ssh 命令中使用简单引号和双引号中的 Python 辅助答案