我正在尝试在 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" 类型构造中引用