在嵌套的单引号、反引号和引号中转义美元符号

Escaping dollar sign inside nested single quote, backtick, and quote

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

这里是调用单个包名;有效:

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

如果我像这样从单行 "file" 进行管道传输,它将不再起作用:

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

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

形式

主要有两个问题:

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

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

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

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

您在 shell 命令中的 Perl 脚本中的 shell 命令中有格式字符串。这种层级的嵌套使得转义变得相当困难,所以最好的解决办法是摆脱不必要的层级。

在这里,最简单的方法是去掉内部的 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)'