通过bash和ssh逐字传递引号和其他特殊字符

我想运行一个SSH命令,它将调用远程机器上的一个脚本,将一些Lua代码写入一个文件。

我有这个在bash下执行的脚本命令:

ssh bob writelua.sh '{version=1,{["foo"]=17}}'

writelua.sh 看起来像这样:

echo "return $1" > bar.lua

然而,最终结果是 bar.lua 内容为:

return version=1

我原本以为单引号可以防止所有解释。如何编辑脚本并转义以无害地传递原始Lua代码?

点赞
用户548225
用户548225

使用 heredoc避免所有过多的引用

ssh -T bob << \EOF
    writelua.sh '{version=1,{["foo"]=17}}'
EOF

这将发送原始脚本到远程主机,并在远程主机上解释。

2013-10-14 17:36:51
用户1126841
用户1126841

单引号可以防止在 本地 主机上解释。远程主机看到的是以下命令行:

writelua.sh {version=1,{["foo"]=17}}

其中包含大括号扩展。你需要第二组引号,以便第一组单引号传递到远程主机中。

ssh bob writelua.sh "'{version=1,{[\"foo\"]=17}}'"

如你所见,引号开始变得难以操纵。更好的解决方案是,直接复制包含以下内容的脚本:

writelua.sh '{version=1,{["foo"]=17}}'

到远程主机上,并在远程执行。


以下是一个使用 $'...' 引号的例子:

ssh bob writelua.sh $'{version=1,{[\'foo\']=17}}'
2013-10-14 17:37:39
用户5362795
用户5362795

当命令变得太复杂,特别是需要进行大量转义时,我更喜欢在一个临时脚本中生成命令,然后根据需要在本地或者远程通过 SSH 执行。

但是还有另一种方法:使用echo来将命令存储在一个变量中,并且利用三个特点:

  • 单引号不进行变量扩展且允许使用双引号,因此您可以无需转义$"来包含类似于"$myvar"的内容。
  • 双引号允许变量扩展和单引号,这意味着您可以包含类似于animals='all'; echo love $animals,以便将$animals替换为其值,而无需转义'
  • 单引号或双引号括起来的字符串可以通过将它们放在一起简单地连接起来。

作为一个例子,如果我想在远程机器上执行以下命令:

source /my-env.sh; perl -MMYLIB::DB -e 'my $t=db_list("name", 1553786458); print "@$t"'

但是我想在本地变量中传递1553786458的值,而不是直接将其写入命令中:

now=`date +%s`

我们可以这样写:

get_list=`echo 'source /my-env.sh; perl -MMYLIB::DB -e' "'my " '$t=db_list("name", ' "$now" '); print "@$t"' "'"`

您可以看到,单引号和双引号交替出现,因此我们不需要进行任何转义! 它们之间不需要用空格分隔,但在本例中,这有助于提高可读性,并且不会影响结果。

现在,我们可以执行:

ssh user@host $get_list

仍然不能保证这种方法总是有效,因此,一旦构建了您的命令,最安全的方法是将其复制到一个文件中。

2019-03-28 16:01:54
用户124951
用户124951

如果您会使用 Perl...

use Net::OpenSSH;
my $ssh = Net::OpenSSH->new("bob");
$ssh->system('writelua.sh', '{version=1,{["foo"]=17}}')
  or die $ssh->error;

Net::OpenSSH会为您处理 引号 的问题。

2019-03-29 14:21:54