2014-01-06 40 views
3

我试图在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运行的Perl 5.8.8 5

+3

在你的第三个例子中,$ _在引号之外,这意味着它在字符串形成之前被赋值并传递给'perl -ne' – njzk2

+4

这是一个shell特性,与Perl无关。试试'echo foo; echo $ _'(在我的bash或sh上重复两次'foo':'$ _'是最后一个参数)。所以重要的问题是:你在用什么外壳? – amon

+0

我正在使用bash。 – chilemagic

回答

11

你的shell,'chomp; print "'$_'\n"'后的字符串这是

  1. chomp; print "(单引号内的第一顺序)的级联,
  2. 它的变量值$_
  3. \n"(单引号内的第二个序列)。

bash,$_“...展开后扩展到上一个命令的最后一个参数......”。由于这恰好是shortlist.txt,下面是传递给perl

chomp; print "shortlist.txt\n" 

例如,

$ echo foo 
foo 

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

您可以使用单引号的俏皮话来保护你的Perl代码被shell评估。在此命令:

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

$_之前关闭单引号,所以外壳扩展$_the last argument to the previous command。在你的情况,这正好是你输入文件的名字,但如果你第一次运行不同的命令的输出会有所不同:

$ echo foo 
$ perl -ne 'chomp; print "'$_'\n"' shortlist.txt 
foo 
foo 
foo 
foo 
foo 
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 
+0

Nit:'perl -nle'chomp; print $ _''在使用'$ _'时非常不一致,而'-nl'则暗示'chomp',所以'perl -nle'chomp; print $ _''变成'perl -nle'chomp; print''然后'perl -nle'print'',然后'perl -ple 1',然后'perl -ple1'。但为什么'-l'? 'perl -pe1'或'cat'。我不知道你为什么建议这些简化之一,而不是其他人。 (我不知道你为什么建议任何简化。) – ikegami

+0

尽管实际的代码很愚蠢,但它是OP使用的。我展示了一些使用原始代码对OP进行特定事情的最少更改的事情。也许他简化了他的脚本以完成更大的任务。 *耸耸肩* –

+0

你错过'perne -MO = Deparse'chomp;打印''$ _'\ n“'shortlist.txt',并且是这段代码有点傻,但它仅仅是为了说明问题而简化了一个更大的任务。谢谢! – chilemagic