为什么Perl的glob会在每次其他调用时返回undef?

时间:2009-08-13 21:19:53

标签: perl unix environment-variables glob

我不一定会寻找更好的方法来做到这一点,而是对输出的解释将非常感激。最近,一位资深程序员问我为什么他的代码有效,但仅限于一个实例。我发现的是它每隔一段时间都有效。这是我的例子:

#!/usr/bin/perl -w
use strict;

my @list_env_vars = (
    '$SERVER',
    '$SERVER',
    '$SERVER',
    '$SERVER',
    '$SERVER',
    '$SERVER',
);

foreach (@list_env_vars){
    print "$_ = ".glob()."\n";
}

perl 5.004的输出:

$SERVER = UNIX_SERVER
$SERVER =
$SERVER = UNIX_SERVER
$SERVER =
$SERVER = UNIX_SERVER
$SERVER =

或输出perl 5.10:

$SITE = $SITE
Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14.
$SITE =
$SITE = $SITE
Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14.
$SITE =
$SITE = $SITE
Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14.
$SITE =

我个人从未以这种方式使用过glob(),所以我没有能力回答他。我阅读了perldoc glob文档,并按照该页面上的File::Glob链接进行操作,但仍找不到任何可以解释输出的内容。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:13)

标量上下文中的

glob

  

在标量上下文中,glob遍历这样的文件名扩展,当列表用完时返回undef。

foreach (@list_env_vars){
    print "$_ = ".glob()."\n";
}

glob()确实存在glob($_)。每次迭代,$_都包含字符串$SERVER。鉴于环境变量未发生变化,$SERVER将扩展为相同的字符串。第一次,返回此字符串。接下来,列表已用尽,因此返回undef。第三次,我们重新开始。 ...

澄清:第二次调用的参数与第一次调用的参数相同并不重要,因为无法重置glob的迭代器。 / p>

使用以下示例可以更清楚地看到这一点(当前目录包含文件'1.a',1.b','2.a'和'2.b'):

#!/usr/bin/perl -w
use strict;

my @patterns = (
    '*.a',
    '*.b',
);

for my $v ( @patterns ) {
    print "$v = ", scalar glob($v), "\n";
}

输出:

C:\Temp> d
*.a = 1.a
*.b = 2.a

我建议通过%ENV哈希来访问环境变量:

my @list_env_vars = ($ENV{SERVER}) x 6;

my @list_env_vars = @ENV{qw(HOME TEMP SERVER)};

答案 1 :(得分:4)

顺便提一下,为什么在5.004你得到一个变量扩展,而在5.10你只是得到你的文字字符串,是因为在旧的perl上,glob()是由系统shell执行的,就像一个副作用执行变量扩展。从perl 5.6开始,glob()使用File::Glob模块来完成工作本身,没有shell,并且不扩展环境变量(glob从未打算这样做)。 %ENV是了解环境的正确方法。

答案 2 :(得分:0)

关于旧行为的注释,wiki为了您的方便(以及我有完整的标记范围,没有500-char限制):

在文档(glob<*globbything*>perl56delta)中提到了perlop-f glob在5.6中发生更改的事实,但唯一真实的关于它以前的工作原理的来源是perlop的5.6之前的版本。这是5.005的相关位:

  

示例:

while (<*.c>) {
    chmod 0644, $_;
}
     

相当于

open(FOO, "echo *.c | tr -s ' \t\r\f' '\\012\\012\\012\\012'|");
while (<FOO>) {
    chop;
    chmod 0644, $_;
}
     

事实上,它目前以这种方式实施。 (这意味着除非您的计算机上有csh(1),否则它不会对包含空格的文件名起作用。)

嘿,那是非常邪恶的东西。无论如何,如果你发现自己想要查询这样的旧perldocs,只需转到search.cpan.org,调出perl发行版,使用下拉列表选择旧版本,然后点击进入doc你需要的。 perl本身并不真正受到CPAN的“整理”;目前从5.004开始的所有内容都可以使用而无需点击BackPan。