在嵌套的单引号、反引号和引号中转义美元符号
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
.
形式
主要有两个问题:
- 您需要以某种方式将
'
放入 Perl 代码中的字符串中,该字符串已用 '
引用 shell.
- 您需要在反引号中转义
$
,因为它们对 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)'
我想在文件的每一行上使用 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
.
主要有两个问题:
- 您需要以某种方式将
'
放入 Perl 代码中的字符串中,该字符串已用'
引用 shell. - 您需要在反引号中转义
$
,因为它们对 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)'