如何在使用SSH运行远程脚本文件时保留带空格的参数?

5
我发现当我在本地运行脚本时,比如说:

./run.sh a "b c"

当在run.sh中使用"$@"时,它将识别两个参数。但是,当通过ssh在远程机器上使用时,情况就不同了。

ssh user@host ./run.sh a "b c"

那么我应该如何实现这个呢?

如果您将整个命令用引号括起来,例如 ssh user@host './run.sh a "b c"',它是否有效? - melpomene
1
@Lewis Chan:在远程机器上执行时,你遇到了什么错误? - User123
3个回答

14
了解问题:您当前的命令 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

顺便说一下,通常echo输出某些内容并不是发现你的参数被如何解析的好方法,因为它只是将其参数使用空格连接起来。但由于在创建远程命令时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

0
尝试这个: < p> ssh user@host 'bash -c "./run.sh a \"b c\""'


虽然这段代码可能回答了问题,但提供关于为什么解决问题的额外上下文会提高答案的长期价值。 - Alexander

0

我遇到了与其他人指出的类似问题,使用双引号而不是单引号帮助我解决了这个问题。

ssh ubunut@12.3232.34.232 "ls -a"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接