我开始自学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");
答案 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”语法,通常使用or
和and
作为短路运算符。参数检查变为
@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){
...
}