【问题标题】:Passing quotes and other special characters literally through bash and ssh通过 bash 和 ssh 逐字传递引号和其他特殊字符
【发布时间】:2013-10-22 08:23:27
【问题描述】:

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

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

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

writelua.sh 看起来像这样:

echo "return $1" > bar.lua

然而,最终结果是bar.lua 具有以下内容:

return version=1

我原以为单引号会阻止所有解释。如何编辑脚本并转义以通过原始 Lua 代码安然无恙?

【问题讨论】:

  • 有多个点可以解释,因此对于每个点,可能需要一层转义:ssh bob "writelua.sh '{version=1,{[\"foo\"]=17}}'"(或ssh bob 'writelua.sh "{version=1,{[\"foo\"]=17}}"'
  • 也许它又经历了一层“解释”。您是否尝试转义单引号('{version=1,{["foo"]=17}}\'

标签: linux bash shell ssh lua


【解决方案1】:

如果你可以使用 Perl...

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

Net::OpenSSHquoting 为您处理一切。

【讨论】:

    【解决方案2】:

    当它变得太复杂时,特别是有很多转义时,我更喜欢在临时脚本上生成命令并根据需要通过 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
    

    仍然不能保证这种方法总是有效,所以一旦你构建了你的命令,最安全的选择是将它复制到一个文件中。

    【讨论】:

      【解决方案3】:

      使用heredoc避免所有过度引用

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

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

      【讨论】:

      • @Phrogz:相关信息请查看stackoverflow.com/questions/2374276/…
      • 我刚刚在heredoc上面试过,在远程主机上的bar.lua中得到了return {version=1,{["foo"]=17}}
      • 如果您希望将引号写入文件本身,您可以将writelua.sh 修改为echo "return '$1'"。 (从技术上讲,引号被传递到远程主机,在将$1 设置为writelua.sh 之前,它们会被剥离,因此您需要重新添加它们。)
      【解决方案4】:

      单引号防止在 local 主机上进行解释。远程主机看到命令行

      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}}'
      

      【讨论】:

      • 如果我的内容中有单引号怎么办?我不能在我的单引号中加上单引号,甚至转义。 (对吧?)
      • 如果您的内容中有单引号,最好简单地编写一个复制的小脚本。 bash 有另一种引用机制,可以包含单引号 ($'\'foo\''),但最好停止滥用可怜的命令行并将其包装在脚本中。
      • 不幸的是,我无权访问本地文件系统,因此我无法编写要调用的文件。我只有执行命令的能力。 ://
      • 同样的引用问题也适用于此处文档的内容。
      • @chepner 没有硬编码,没有。 os.execute(string.format('ssh %s writelua.sh "\'%s\'"',server,lua));所以,现在lua 需要没有单引号,并且双引号被转义。适用于我目前有限、可控的情况。
      猜你喜欢
      • 1970-01-01
      • 2015-11-22
      • 1970-01-01
      • 2013-08-14
      • 1970-01-01
      • 2018-04-29
      • 2012-09-06
      • 1970-01-01
      • 2011-04-12
      相关资源
      最近更新 更多