Perl - 在字符串中使用未初始化的值

时间:2013-04-19 16:35:53

标签: perl

我开始自学Perl,在一些谷歌搜索的帮助下,我能够将一个脚本放在一起,打印出给定目录中的文件扩展名。该代码运行良好,但有时会抱怨以下内容:

Use of uninitialized value $exts[xx] in string eq at get_file_exts.plx

我尝试通过初始化我的数组来纠正这个问题,如下所示:myexex =();但这没有按预期工作。

#!/usr/bin/perl
use strict; 
use warnings;
use File::Find;

#Check for correct number of arguments
if(@ARGV != 1) {
    print "ERROR: Incorrect syntax...\n";
    print "Usage: perl get_file_exts.plx <Directory>\n";
    exit 0;
}

#Search through directory
find({ wanted => \&process_file, no_chdir => 1 }, @ARGV);

my @exts;

sub process_file {
    if (-f $_) {
        #print "File: $_\n";
        #Get extension
        my ($ext) = $_ =~ /(\.[^.]+)$/;

        #Add first extension
        if(scalar @exts == 0) {
            push(@exts, $ext);
        }

        #Loop through array
        foreach my $index (0..$#exts) {
            #Check for match
            if($exts[$index] eq $ext) {
                last;
            } 
            if($index == $#exts) {
                push(@exts, $ext);
            }
        }
    } else {
        #print "Searching $_\n";
    }
}

#Sort array
@exts = sort(@exts);

#Print contents
print ("@exts", "\n");

4 个答案:

答案 0 :(得分:2)

该警告正在抱怨$exts[xx]的内容,而不是@exts本身。

实际上$ext可以是undef,当文件名与正则表达式不匹配时,例如 README

尝试:

    my ($ext) = $_ =~ /(\.[^.]+)$/ or return;

答案 1 :(得分:2)

您需要测试是否找到了扩展程序。

此外,您不应该为数组编制索引。你也不需要管理'推'就行了。它不是Perl的方式。你的for循环应该像这样开始:

sub process_file {
  if (-f $_) {
    #print "File: $_\n";
    #Get extension
    my ($ext) = $_ =~ /(\.[^.]+)$/;

    # If we found an extension, and we have not seen it before, add it to @exts
    if ($ext) {
      #Loop through array to see if this is a new extension
      my $newExt = 1;
      for my $seenExt (@exts) {
        #Check for match
        if ($seenExt eq $ext) {
          $newExt = 0
          last;
        }
      }

      if ($newExt) {
        push @exts,$ext;
      }
    }
  }
}

但你真正想做的是使用哈希表记录你是否看到了扩展名

# Move this before find(...); if you want to initialize it or you will clobber the 
# contents
my %sawExt;

sub process_file {
  if (-f $_) {
    #print "File: $_\n";
    # Get extension
    my ($ext) = $_ =~ /(\.[^.]+)$/;

   # If we have an extension, mark that we've seen it
   $sawExt{$ext} = 1
     if $ext;
  }
}

# Print the extensions we've seen in sorted order
print join(' ',sort keys %sawExt) . "\n";

甚至

sub process_file {
  if (-f $_ && $_ =~ /(\.[^.]+)$/) {
    $sawExt{$1} = 1;
  }
}

或者

sub process_file {
  $sawExt{$1} = 1
    if -f && /(\.[^.]+)$/;
}

一旦你开始用Perl思考,这就是写它的自然方式

答案 2 :(得分:1)

主要问题是您没有考虑不包含点的文件名,所以

my ($ext) = $_ =~ /(\.[^.]+)$/;

$ext设置为undef

尽管有警告,但处理仍在继续,将undef评估为空字符串,未能在@exts中找到,因此也将undef渗透到数组中。

让代码正常工作的最小变化是替换

my ($ext) = $_ =~ /(\.[^.]+)$/;

return unless /(\.[^.]+)$/;
my $ext = $1;

但是这里有一些Perl课程需要学习。 使用教导好的程序是评论良好的程序。那是在必须编写高效但难以理解的代码的时代,但不再是真的。您应该编写尽可能清晰的代码,并且只有在您必须编写一些不易解释的内容时才添加注释。

你应该记住并使用Perl习语,并试着忘记你所知道的大多数C.例如,Perl接受“here document”语法,通常使用orand作为短路运算符。参数检查变为

@ARGV or die <<END;
ERROR: Incorrect syntax...
Usage: perl get_file_exts.plx <Directory>
END

Perl允许清晰但简洁的编程。这就是我写wanted子程序

的方法
sub process_file {

  return unless -f and /(\.[^.]+)$/;

  my $ext = $1;

  foreach my $index (0 .. $#exts) {
    return if $exts[$index] eq $ext;
  }

  push @exts, $ext;
}

答案 3 :(得分:0)

在访问$exts[xx]之前使用exists

exists已弃用,但@chrsblck指出:

  

请注意,数组值存在的调用已被弃用且可能已弃用   将在Perl的未来版本中删除。

但您应该能够通过以下方式检查它是否存在(而不是0""):

if($exts[index] && $exts[$index] eq $ext){
   ...
}