通过 ssh 执行 sh -c 的变量扩展

通过 ssh 执行 sh -c 的变量扩展

我正在尝试在 LXC 容器中通过 SSH 通过 sh -c 执行命令。由于涉及 lxc-attach 我必须sh -c这样使用:ssh <host> "lxc-attach -- sh -c \"<command>;<command>\""。这适用于大多数情况。但是当我尝试在命令中使用文字环境变量时,该变量不断扩展。

问题可以简化为:我想打印一个文字$HOME

当地的:

user@local:~$ sh -c 'echo $HOME'
/home/user
# Despite single quote the variable gets expanded, one has to escape the $ sign
user@local:~$ sh -c 'echo \$HOME'
$HOME

到目前为止一切顺利,但是当我通过 SSH 尝试时偏僻的

user@local:~$ ssh remote "sh -c 'echo \$HOME'"
/root
user@local:~$ ssh remote 'sh -c 'echo \$HOME''

user@local:~$ ssh remote "sh -c \'echo \$HOME\'"
/root': 1: Syntax error: Unterminated quoted string

我尝试了多种转义变量的变体。它不断扩展,没有打印任何内容或出现错误。

答案1

SSH 始终在远程运行 shell 来处理您给出的命令行。看: ssh远程命令行参数如何解析

$ ssh remote "sh -c 'echo \$HOME'"
/root

本地shell撤销一层引号,变成\$SSH$ 发送sh -c 'echo $HOME'到远程在shell中运行,sh显式启动展开$HOME

$ ssh remote 'sh -c 'echo \$HOME''

这与

$ ssh remote 'sh -c echo' \$HOME              # or
$ ssh remote 'sh -c echo' '$HOME'

请注意,空格未加引号(echo原件中也未加引号,但这并不重要)。

SSH 将它获取的参数与空格连接起来,然后将字符串发送sh -c echo $HOME到远程。通过内壳传递的结果命令-c就是 command echo。的扩展$HOME进入$0那个内部sh

$ ssh remote "sh -c \'echo \$HOME\'"
/root': 1: Syntax error: Unterminated quoted string

在这里,本地 shell 再次变成\$$并且 SSH 将字符串发送 sh -c \'echo $HOME\'到远程,其中 SSH 启动的 shell 解析这些反斜杠并sh使用参数-c, 'echo, /home/username'(展开$HOME)运行命令。这 sh看到命令'echo确实有一个未终止的带引号的字符串。

你需要这样的东西

$ ssh localhost 'sh -c "echo \\\$HOME"'
$HOME

sh -c以保护本地 shell(上面的单引号)、由 SSH 启动的 shell(反斜杠)以及您启动的 shell (另一级反斜杠,一个用于\,一个用于)的扩展$

或者用单引号代替一层反斜杠:

$ ssh localhost 'sh -c '\''echo \$HOME'\'
$HOME

通过文件或(引用的)此处文档或类似文件传递命令会更容易:

$ ssh localhost 'sh -s' <<'EOF'
echo '$HOME'
EOF
$HOME

也可以看看:在 ssh $host $FOO 和 ssh $host "sudo su user -c $FOO" 类型构造中引用

相关内容