[英]Why is '$_' the same as $ARGV in a Perl one-liner?
我在尝试在 Perl 单行中打印单引号时遇到了这个问题。 我最终发现你必须用'\\''
来逃避它们。 这是一些代码来说明我的问题。
让我们从打印文本文件开始。
perl -ne 'chomp; print "$_\n"' shortlist.txt
red
orange
yellow
green
blue
现在让我们为每一行打印文件名。
perl -ne 'chomp; print "$ARGV\n"' shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
然后我们可以在每一行周围添加单引号。
perl -ne 'chomp; print "'$_'\n"' shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
shortlist.txt
等等,没有用。 让我们再试一次。
perl -ne 'chomp; print "'\''$_'\''\n"' shortlist.txt
'red'
'orange'
'yellow'
'green'
'blue'
所以我现在开始工作了。 但我仍然对为什么 '$_' 计算为程序名称感到困惑。 也许这很简单,但有人可以解释或链接到某些文档吗?
编辑:我在 Red Hat 5 上运行 Perl 5.8.8
对你的外壳, 'chomp; print "'$_'\\n"'
'chomp; print "'$_'\\n"'
结果是一个字符串的连接
chomp; print "
chomp; print "
(单引号内的第一个序列),$_
的值,以及\\n"
(单引号内的第二个序列)。 在bash
, $_
"... 扩展到上一个命令的最后一个参数,扩展后。..."。 由于这恰好是shortlist.txt
,因此将以下内容传递给perl
:
chomp; print "shortlist.txt\n"
例如,
$ echo foo
foo
$ echo 'chomp; print "'$_'\n"'
chomp; print "foo\n"
请注意,不应使用上述机制将值传递给 Perl 单行程序。 您不应该从 shell 生成 Perl 代码。 请参阅如何在 -n 或 -p 模式下使用 Perl 处理选项? 了解如何为单行提供参数。
您在单行中使用单引号来保护您的 Perl 代码不被 shell 评估。 在这个命令中:
perl -ne 'chomp; print "'$_'\n"' shortlist.txt
您关闭$_
之前的单引号,因此 shell 将$_
扩展到上一个命令的最后一个参数。 在您的情况下,这恰好是您输入文件的名称,但如果您先运行不同的命令,输出会有所不同:
$ echo foo
$ perl -ne 'chomp; print "'$_'\n"' shortlist.txt
foo
foo
foo
foo
foo
正是出于这个原因,我尽量避免在一个班轮中使用引号。 当我可以时,我使用广义引用:
% perl -ne 'chomp; print qq($_\n)'
虽然我可以避免使用-l
开关来免费获得换行符:
% perl -nle 'chomp; print $_'
如果我不理解单行,我使用-MO=Deparse
来看看 Perl 认为它是什么。 前两个是您期望的:
% perl -MO=Deparse -ne 'chomp; print "$_\n"' shortlist.txt
LINE: while (defined($_ = <ARGV>)) {
chomp $_;
print "$_\n";
}
-e syntax OK
% perl -MO=Deparse -ne 'chomp; print "$ARGV\n"' shortlist.txt
LINE: while (defined($_ = <ARGV>)) {
chomp $_;
print "$ARGV\n";
}
-e syntax OK
你在你看到问题的地方看到了一些有趣的东西。 该变量在perl
看到它之前就消失了,并且在它的位置有一个常量字符串:
% perl -MO=Deparse -ne 'chomp; print "'$_'\n"' shortlist.txt
LINE: while (defined($_ = <ARGV>)) {
chomp $_;
print "shortlist.txt\n";
}
-e syntax OK
您的修复也很奇怪,因为Deparse将变量名称放在大括号中以将其与旧的包说明符'
分开:
% perl -MO=Deparse -ne 'chomp; print "'\''$_'\''\n"' shortlist.txt
LINE: while (defined($_ = <ARGV>)) {
chomp $_;
print "'${_}'\n";
}
-e syntax OK
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.