了解问题:您当前的命令 ssh user@host ./run.sh a "b c" 发生的情况是本地 shell 将命令解析为“单词”(应用和删除它看到的任何引号和/或转义),并得到“ssh ”、“user@host”、“./run/sh”、“a”和“b c”。它将第一个 (ssh) 作为命令,并将其余的作为参数传递给它。 ssh 将“user@host”作为 ssh 到的位置,并且(这是关键的事情)它只是将其余部分粘在一起(用空格分隔)作为远程命令运行。这将“./run.sh a b c”作为远程命令。然后将其传递给远程 shell,后者(因为引号现在已经消失)将“a”、“b”和“c”解释为单独的参数。
简而言之:引号被本地 shell 应用和删除,而不是远程 shell(这是你关心的那个)。
解决方案:引用或转义引号,以便本地 shell 将它们视为要传递给远程 shell 的数据。本质上,这意味着您需要两个级别的引用/转义,以便本地 shell 将应用(和删除)一个级别,而远程 shell 将应用(和删除)第二个级别。
这是一个简单、干净的方法:
ssh user@host './run.sh a "b c"'
本地 shell 应用并删除单引号,因此远程 shell 应用双引号。请注意,引号通常不会嵌套在它们自己/彼此之间,但是由于双引号在单引号字符串中没有特殊含义,因此在这种情况下可以使用。您也可以对两个级别使用双引号,但您需要转义内引号:
ssh user@host "./run.sh a \"b c\""
实际上,其中的外部双引号实际上并没有在这里做任何事情(它们使整个事情成为 ssh 的一个参数,但如果它们是多个参数,那么它们无论如何都会被粘在一起,所以.. .)。您实际上可以删除它们:
ssh user@host ./run.sh a \"b c\"
实际上有很多方法可以做到这一点,结合本地和远程 shell 上的各种引用/转义选项:
ssh user@host ./run.sh a '"b c"'
ssh user@host "./run.sh a 'b c'"
ssh user@host './run.sh a b\ c'
ssh user@host ./run.sh a b\\ c
顺便说一句,一般来说,echoing 是一个非常糟糕的方法来找出你的参数是如何被解析的,因为它只是将它的参数和它们之间的空格粘在一起。但由于这与 ssh 在创建远程命令时所做的相同,您可以将 ssh user@host 替换为 echo 以查看实际传递给远程 shell 的内容:
$ echo ./run.sh a "b c"
./run.sh a b c
$ echo './run.sh a "b c"'
./run.sh a "b c"
$ echo "./run.sh a \"b c\""
./run.sh a "b c"
$ echo "./run.sh a 'b c'"
./run.sh a 'b c'
$ echo ./run.sh a b\\ c
./run.sh a b\ c