为什么'$ _'与Perl单行中的$ ARGV相同?

时间:2014-01-06 17:25:51

标签: perl bash sh

我试图在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

3 个答案:

答案 0 :(得分:12)

您在单行中使用单引号来保护您的Perl代码不被shell评估。在此命令中:

perl -ne 'chomp; print "'$_'\n"' shortlist.txt

您在$_之前关闭单引号,因此shell会将$_展开为the last argument to the previous command。在您的情况下,这恰好是输入文件的名称,但如果您先运行不同的命令,输出会有所不同:

$ echo foo
$ perl -ne 'chomp; print "'$_'\n"' shortlist.txt
foo
foo
foo
foo
foo

答案 1 :(得分:11)

对于你的shell,'chomp; print "'$_'\n"'会产生一个串联的字符串

  1. chomp; print "(单引号内的第一个序列),
  2. 其变量$_
  3. 的值
  4. \n"(单引号内的第二个序列)。
  5. bash中,$_“扩展到上一个命令的最后一个参数,扩展后......”。由于这恰好是shortlist.txt,因此以下内容传递给perl

    chomp; print "shortlist.txt\n"
    

    例如,

    $ echo foo
    foo
    
    $ echo 'chomp; print "'$_'\n"'
    chomp; print "foo\n"
    

答案 2 :(得分:5)

出于这个原因,我尽量避免在一个衬里中引用。我可以使用广义引用:

% 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