File::Find
和 wanted
子程序 这个问题比原始标题(“原型和子程序的前向声明”)简单得多。我希望答案无论多么简单,都能帮助我理解子程序/函数,原型和作用域以及File::Find
模块。
使用Perl,子程序几乎可以出现在任何地方,你通常不需要进行前向声明(除非sub声明了一个原型,我不知道如何在Perl中采用“标准”方式) 。对于我通常使用Perl做的事情,这些不同的运行方式somefunction
:
sub somefunction; # Forward declares the function
&somefunction;
somefunction();
somefunction; # Bare word warning under `strict subs`
我经常使用find2perl
来生成代码,我将这些代码整合到脚本的一部分中。这可能是糟糕的风格,现在我的脏衣服是公开的,但所以它是:-)对于File::Find
,wanted
函数是必需的子例程 - find2perl
创建它并添加{{ 1}}到它创建的结果脚本。有时,当我编辑脚本时,我会从sub wanted;
中删除“sub
”,最终会显示为sub wanted
或&wanted;
。但是如果没有wanted();
前向声明表单,我会收到此警告:
sub wanted;
我的问题是:为什么会发生这种情况,这是一个真正的问题?这只是“警告”,但我想更好地理解它。
Use of uninitialized value $_ in lstat at findscript.pl line 29
位于$_
内。如果我使用sub wanted {}
代替wanted();
,为什么不定义? sub wanted;
是否在某处使用原型?我错过了wanted
中明显的东西吗?Find/File.pm
返回代码引用吗? (???)我的猜测是前向声明表单以某种方式“初始化”wanted
,以便第一次使用时没有空的默认变量。我想这就是原型 - 即使是Perl原型,如它们存在 - 也会起作用。我尝试使用Perl源代码来了解使用wanted
而不是sub
调用函数时sub function
正在做什么,但这可能超出了我的目的。
非常感谢任何帮助深化(并加快)我对此的理解。
编辑:这是我使用function()
输出创建的recent example script here on Stack Overflow。如果您从find2perl
中移除sub
,则会收到相同的错误。
编辑:正如我在下面的评论中所指出的那样(但我也会在此处标记):几个月来我一直在使用Path::Iterator::Rule
代替sub wanted;
。它需要File::Find
,但我从不必在具有奇数,“永不升级”,perl >5.10
仅限策略的网站上部署生产代码,因此5.8.*
已成为我永远不想做的模块之一没有。同样有用的是Path::Class
。欢呼声。
答案 0 :(得分:12)
我不是File :: Find的忠实粉丝。它只是不起作用正确。 find
命令不会返回文件列表,因此您必须在find
中使用非本地数组变量来捕获您的文件列表发现(不好),或将整个程序放在想要的子程序中(更糟糕的是)。另外,单独的子例程意味着您的逻辑与find
命令是分开的。这太丑了。
我所做的是在wanted
命令中内联我的find
子例程。子程序保留在查找中。另外,我的非本地数组变量现在只是我find
命令的一部分而且看起来不那么糟糕
以下是我处理File::Find
的方式 - 假设我想要.pl
后缀的文件:
my @file_list;
find ( sub {
return unless -f; #Must be a file
return unless /\.pl$/; #Must end with `.pl` suffix
push @file_list, $File::Find::name;
}, $directory );
# At this point, @file_list contains all of the files I found.
这与:
完全相同my @file_list;
find ( \&wanted, $directory );
sub wanted {
return unless -f;
return unless /\.pl$/;
push @file_list, $File::Find::name;
}
# At this point, @file_list contains all of the files I found.
衬里看起来更好看。而且,它将我的代码保持在一起。另外,我的非本地数组变量看起来并不那么怪异。
我也喜欢以这种特殊的方式利用更短的语法。通常,我不喜欢使用推断的$_
,但在这种情况下,它使代码更容易阅读。我原来的通缉与此相同:
sub wanted {
my $file_name = $_;
if ( -f $file_name and $file_name =~ /\.pl$/ ) {
push @file_list, $File::Find::name;
}
}
File::Find
使用并不是那么棘手。你只需要记住:
return
转到下一个文件。$_
包含没有目录的文件名,您可以使用它来测试文件。$File::Find::name
。$File::Find::dir
。最简单的方法是将所需的文件推送到数组中,然后在程序中使用该数组。
答案 1 :(得分:5)
从sub
移除sub wanted;
只会调用wanted
函数,而不是前向声明。
但是,wanted
函数尚未设计为直接从您的代码中调用 - 它被设计为由File :: Find调用。 File :: Find会在调用它之前填充$_
等有用的东西。
此处无需转发声明wanted
,但如果您要删除转发声明,请删除整个sub wanted;
行 - 而不仅仅是单词sub
。
答案 2 :(得分:2)
我建议使用File::Find::Wanted
中的File::Find
功能,而不是find_wanted
。
find_wanted
有两个参数:
find_wanted
返回一个包含它找到的文件名列表的数组。
我使用以下代码查找计算机上某些目录中的所有JPEG文件:
my @files = find_wanted( sub { -f && /\.jpg$/i }, @dirs );
对于那些可能需要它的语法的一些语法的解释:
sub {...}
是一个匿名子程序,其中...
被替换为子程序的代码。
-f
检查文件名是否指向“普通文件”
&&
是布尔和
/\.jpg$/i
是一个正则表达式,用于检查文件名是否以.jpg
结尾(不区分大小写)。
@dirs
是一个包含要搜索的目录名的数组。也可以搜索单个目录,在这种情况下标量也可以工作(例如$dir
)。
答案 3 :(得分:0)
为什么不使用open
并调用外壳程序find
?用户可以将$findcommand
(如下)编辑为所需内容,也可以根据传递给脚本的参数和选项进行实时定义。
#!/usr/bin/perl
use strict; use warnings;
my $findcommand='find . -type f -mtime 0';
open(FILELIST,"$findcommand |")||die("can't open $findcommand |");
my @filelist=<FILELIST>;
close FILELIST;
my $Nfilelist = scalar(@filelist);
print "Number of files is $Nfilelist \n";