10

File::Find wanted サブルーチン

この質問は、元のタイトル (「プロトタイプとサブルーチンの前方宣言」!) よりもはるかに単純です。答えが単純であっても、サブルーチン/関数、プロトタイプ、スコープ、およびFile::Findモジュールを理解するのに役立つことを願っています。

Perl では、サブルーチンはほとんどどこにでも表示でき、通常は前方宣言を行う必要はありません (ただし、サブルーチンがプロトタイプを宣言する場合を除きます。これは、Perl で「標準的な」方法で行う方法がわかりません)。私が通常Perlで行うことについては、これらの異なる実行方法の間にほとんど違いはありませんsomefunction:

sub somefunction;  # Forward declares the function
&somefunction; 
somefunction();
somefunction;   # Bare word warning under `strict subs`

find2perl私は、スクリプトの一部にクリブ/ハックするコードを生成するためによく使用します。これは悪いスタイルである可能性があり、私の汚れた洗濯物は公開されていますが、そうです:-)関数は必須のサブルーチンであるためFile::Find、それを作成し、作成した結果のスクリプトに追加します。時々、スクリプトを編集するときに " " を削除すると、orになります。しかし、前方宣言フォームがないと、次の警告が表示されます。wantedfind2perlsub wanted;subsub 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コード参照を返すからですか?(???)

私の推測ではwanted、最初の使用で空のデフォルト変数がないように、前方宣言フォームが何らかの方法で「初期化」されると思います。これは、プロトタイプ (存在するような Perl プロトタイプでさえ) も同様に機能する方法だと思います。の代わりに をsub使用して関数が呼び出されたときに何が行われているかを把握するために、Perl のソース コードを調べてみましたが、この時点では理解できないかもしれません。sub functionfunction()

これについての私の理解を深める(そしてスピードアップする)助けがあれば、大歓迎です。

編集:の出力を使用して作成した Stack Overflowの最近のサンプル スクリプトを次に示します。find2perlを削除するsubsub wanted;、同じエラーが発生するはずです。

編集:以下のコメントで指摘したように(ただし、ここでもフラグを立てます):数か月間Path::Iterator::RuleFile::Find. 必要perl >5.10ですが、「アップグレードしない」という奇妙でサイトに運用コードを展開する必要はありません。5.8.*ポリシーのみなので、Path::Iterator::Rule絶対に外したくないモジュールの 1 つになりました。も便利ですPath::Class。乾杯。

4

4 に答える 4

17

私は 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.

最も簡単な方法は、必要なファイルを配列にプッシュし、後でその配列をプログラムで使用することです。

于 2013-07-19T21:48:00.523 に答える