【问题标题】:Escaping dollar sign inside nested single quote, backtick, and quote在嵌套的单引号、反引号和引号内转义美元符号
【发布时间】:2018-03-30 19:53:54
【问题描述】:

我想使用 Perl 在文件的每一行上运行 shell 命令。该文件包含包名称,例如firefox

这是对单个包名的调用;它有效:

dpkg-query -W -f='${binary:Package}_${Version}' firefox

如果我像这样从单行“文件”进行管道传输,它将不再起作用:

echo firefox | perl -ne \
  'print `dpkg-query -W -f="${binary:Package}_${Version}" $_` . "\n"'

输出为_\n。那么在这些嵌套引号中转义这些美元的正确方法是什么,以便 dpkg-query 接收逐字字符串 ${binary:Package}_${Version} 而没有 shell 或 bash 将它们解释为“他们的”变量?我尝试了各种排列,但到目前为止无济于事。输出格式应为firefox_59.0.2+build1-0ubuntu0.16.04.1\n

【问题讨论】:

    标签: bash dpkg perl


    【解决方案1】:

    您在 shell 命令中的 Perl 脚本中的 shell 命令中具有格式字符串。这种级别的嵌套使得转义非常困难,因此最好的解决方案是去掉不必要的级别。

    在这里,最简单的方法是去掉内壳命令。您不需要通过 shell 运行 dpkg 命令,可以直接执行它。这将避免必须在 Perl 中处理任何类型的 shell 元字符。例如:

    perl -ne 'chomp; system q(dpkg-query), q(-W), q(-f=${binary:Package}_${Version}), $_; print qq(\n)'
    

    这会将命令输出直接打印到 STDOUT,而不是先捕获它。与使用反引号一样,这不会进行任何错误处理。要获得真正的退出代码,您需要$? >> 8。因此,通过适当的错误处理,命令将如下所示:

    perl -ne '
      chomp;
      @command = (q(dpkg-query), q(-W), q(-f=${binary:Package}_${Version}), $_); 
      system(@command) == 0 or die sprintf qq(Command [%s] exited with status %d\n), qq(@command), $? >> 8;
      print qq(\n)'
    

    【讨论】:

    • 哦,废话,我完全忽略了print `...`(即捕获输出,然后打印它)可以通过对system 的简单调用来替换(即首先不捕获输出) .
    【解决方案2】:

    主要有两个问题:

    1. 您需要以某种方式将 ' 放入 Perl 代码中的字符串中,该字符串已被 ' 引用为 shell。
    2. 您需要在反引号中转义 $,因为它们对 Perl 具有特殊含义。

    让我们先从第二个问题开始。

    dpkg-query -W -f='${binary:Package}_${Version}' firefox
    

    是普通的命令行。用反引号包裹给我们

    print `dpkg-query -W -f='\${binary:Package}_\${Version}' $_` . "\n"
    

    在 Perl 中。

    现在我们想在命令行上将该代码传递给 perl,这需要在 shell 中引用所有这些:

    perl -ne 'print `dpkg-query -W -f='\''\${binary:Package}_\${Version}'\'' $_` . "\n"'
    

    如果这看起来令人困惑,那么原始字符串中的每个' 在引用版本中都会变成'\''。这是因为第一个' 结束了我们所在的单引号字符串,然后\' 指定了一个转义引号,然后' 再次开始了一个带引号的部分。 (如果你仔细观察,你会发现它发生在 SO 的语法高亮中。)

    我们可以应用另一个简化。 $_ 中的传入行仍然包含一个尾随换行符,我们不需要(或不希望:如果$_ 之后有任何内容,它将破坏命令)。我们可以使用-l 选项将其删除,这也使print 默认输出\n

    echo firefox | perl -lne \
      'print `dpkg-query -W -f='\''\${binary:Package}_\${Version}'\'' $_`'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-17
      • 1970-01-01
      相关资源
      最近更新 更多