简体   繁体   English

在嵌套的单引号,反引号和引用内逃脱美元符号

[英]Escaping dollar sign inside nested single quote, backtick, and quote

I would like to use Perl for running a shell command on each line of a file. 我想使用Perl在文件的每一行上运行shell命令。 The file contains package names such as firefox . 该文件包含诸如firefox包名。

Here is the call for a single package name; 这是对单个包名称的调用; it works: 有用:

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

If I pipe from a single-line "file" like this it does not work any more: 如果我从这样的单行“文件”管道它不再起作用:

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

The output is _\\n . 输出为_\\n So what's the right way to escape these dollars inside those nested quotes such that dpkg-query receives the verbatim string ${binary:Package}_${Version} without a shell or bash interpreting them as "their" variables? 那么什么是在这些嵌套引号中逃避这些美元的正确方法,以便dpkg-query接收逐字字符串${binary:Package}_${Version}而没有shell或bash将它们解释为“他们的”变量? I've tried various permutations but to no avail so far. 我尝试了各种排列但到目前为止无济于事。 The output should be of the form firefox_59.0.2+build1-0ubuntu0.16.04.1\\n . 输出应为firefox_59.0.2+build1-0ubuntu0.16.04.1\\n的格式。

You have a format string within a shell command within a Perl script within a shell command. shell命令中的Perl脚本中的shell命令中有一个格式字符串。 This level of nesting makes escaping quite difficult, so the best solution is to get rid of unnecessary levels. 这种嵌套水平使得逃避非常困难,因此最好的解决方案是摆脱不必要的水平。

Here, the simplest way will be to get rid of the inner shell command. 在这里,最简单的方法是摆脱内部shell命令。 You do not need to run the dpkg command through a shell, and could execute it directly. 您不需要通过shell运行dpkg命令,并且可以直接执行它。 This will avoid having to handle any kind of shell metacharacters within Perl. 这将避免在Perl中处理任何类型的shell元字符。 For example: 例如:

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

This will print the command output directly to STDOUT, without capturing it first. 这将直接将命令输出打印到STDOUT,而不首先捕获它。 As with using backticks, this doesn't do any error handling. 与使用反引号一样,这不会进行任何错误处理。 To get the real exit code, you need to $? >> 8 要获得真正的退出代码,您需要$? >> 8 $? >> 8 . $? >> 8 So with proper error handling, the command would look like: 因此,通过适当的错误处理,命令将如下所示:

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

There are two main issues: 有两个主要问题:

  1. You need to somehow get ' into the string in the Perl code, which is already quoted with ' for the shell. 你需要以某种方式获得'成Perl代码,这已经是加引号的字符串'的外壳。
  2. You need to escape $ in the backticks because those have a special meaning to Perl. 你需要在反引号中转义$ ,因为它们对Perl有特殊意义。

Let's start with the second issue first. 让我们先从第二个问题开始吧。

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

is the normal command line. 是正常的命令行。 Wrapping that in backticks gives us 在反引号中包含它给了我们

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

in Perl. 在Perl。

Now we want to pass that code to perl on the command line, which necessitates quoting all of this for the shell: 现在我们想在命令行上将该代码传递给perl,这需要为shell引用所有这些:

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

If this looks confusing, every ' in the original string becomes '\\'' in the quoted version. 如果这看起来令人困惑,原始字符串中的每个'在引用的版本中变为'\\'' That's because the first ' ends the single-quoted string we're in, then \\' specifies a single escaped quote, then ' starts a quoted section again. 那是因为第一个'结束我们所在的单引号字符串,然后\\'指定一个转义引号,然后'再次启动引用部分。 (If you look closely, you can kind of see it happen in SO's syntax highlighting.) (如果你仔细观察,你可以在SO的语法高亮中看到它。)

There's another simplification we can apply. 我们可以应用另一种简化。 The incoming line in $_ still contains a trailing newline, which we don't need (or want: it would break the command if there were anything after $_ ). $_的传入行仍然包含一个我们不需要的尾随换行符(或者想要:如果$_之后有任何内容,它会破坏命令)。 We can remove it with the -l option, which also makes print output a \\n by default: 我们可以使用-l选项将其删除,这也使print输出默认为\\n

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM