为什么Perl会在这里抱怨未终止的字符串?

时间:2011-12-29 01:06:43

标签: perl

我有一个Perl脚本,在HPUX 11i v3下在Perl 5.005下运行正常,并且在我的Ubuntu 11.04盒子上的Perl 5.10下会出现一个小问题。

归结为如下一行:

open (CMD, "do something | grep -E 'sometext$' |");

(它实际上是捕获ps -ef输出以查看进程是否正在运行但我认为这不重要(a)

现在这在HPUX环境中运行良好但是,当我在Ubuntu下试用时,我得到:

sh: Syntax error: Unterminated quoted string

通过插入大量调试语句,我将其跟踪到该违规行,然后开始逐个删除字符,直到它停止抱怨。幸运的是,$是我尝试过的第一个,它不再给我错误,所以我把行改为:

open (CMD, "do something | grep -E 'sometext\$' |");

它运行良好(无论如何在Linux下 - 我没有在HPUX上测试过,因为我今天无法访问该机器 - 如果它确实有效,我会使用这种方法,但我仍然喜欢知道为什么这是一个问题。)

所以很明显$在我的Linux环境下“吞下”关闭的单引号,但显然不在HPUX上。

我的问题很简单,为什么?当然,5.005和5.10之间没有任何大的变化。或者是否存在某种我缺少的配置项?


(a)但是,如果你知道一个更好的方法来做这个没有外部CPAN模块(即只有基线Perl 5.005安装),我会很高兴知道它。

6 个答案:

答案 0 :(得分:7)

$'是一个特殊变量(请参阅perldoc perlvar)。 5.005是很多版本以前的版本,所以有可能在正则表达式引擎中发生了一些变化,使这个变量不同(虽然看起来也是5.005)

至于更好的方法,你至少只能在管道中运行'ps -ef'并在perl中执行'grep'。

答案 1 :(得分:6)

使用以下!!!

use strict;
use warnings;

你会得到

Use of uninitialized value $' in concatenation (.) or string

答案 2 :(得分:4)

后跟任何标点符号(在标准键盘上)的sigil是Perl中的变量,无论它是否为defined。因此,在双引号字符串中[$@][symbol]将始终作为一个标记读取并进行插值,除非该标记被转义。

我觉得你所看到的差异与不同的系统shell有关,而不是与perl的不同版本有关。

考虑你的行:

open (CMD, "do something | grep -E 'sometext$' |");

当perl看到它时,它会将空$'变量插入到双引号字符串中,因此该字符串变为:

open (CMD, "do something | grep -E 'sometext |");

此时,您的shell将处理如下所示的行:

do something | grep -E 'sometext

如果成功或失败将取决于shell关于未终止字符串的规则(某些shell会大声抱怨,其他shell会自动终止字符串)。

如果您在脚本中使用warnings编译指示,则可能会收到有关插入未定义变量的警告。


ps的输出中读取的更简洁,更简洁的方法是:

my @lines = grep /sometext\$/, `ps -ef`;

或使用明确的开放:

my @lines = grep /sometext\$/, do {
   open my $fh, '|-', 'ps -ef' or die $!;
   <$fh>
};

答案 3 :(得分:3)

因为$'是最新版Perl中的特殊变量。

从官方文档(perlvar):

  

$':   跟随上次成功匹配的字符串   模式匹配(不计算BLOCK中隐藏的任何匹配项   由当前BLOCK包围的eval()。

如果没有成功的模式匹配,$'为空,您的语句基本上插入到

open (CMD, "do something | grep -E 'sometext |");

逃离美元符号(适用于Linux的解决方案)也适用于HPUX。

我不确定这个变量何时添加,但我可以确认它存在于Perl 5.8.5中。 What's New for Perl 5.005提及$'(不是新功能),所以我认为它在此之前就已存在。

答案 4 :(得分:2)

你应该在字符串周围使用单引号而不是双引号,因为字符串中没有任何内容应该插入:

open (CMD, q{do something | grep -E 'sometext$' |});

最好是使用open的3参数形式和词法文件句柄:

open my $cmd, '-|', q{do something | grep -E 'sometext$'} or die 'a horrible death';

我没有很好地解释为什么$'被识别为5.10中的特殊变量,但它不是在5.005中。这是出乎意料的。

有没有一个很好的理由你不能升级到像5.14.1这样的东西?即使您不更改系统提供的Perl,也没有明显的理由您无法在其他位置安装最新版本并将其用于所有脚本工作。

答案 5 :(得分:1)

$'是一个特殊变量。

如果您想避免变量扩展,只需使用q()

open (CMD, q(do something | grep -E 'sometext$' |));