camel

なかなか良い仕事をしてくれているid:perlcodesampleだが、今回のこのタイトルはどうかと思う。

というのも、glob()で得られるのはカレントディレクトリのファイル一覧とは限らないし、何よりファイル一覧を取るにはreaddir()という関数が別に存在するからだ。

例えば、以下のようにした場合、得られるのはカレントディレクトリではなくルートディレクトリにあるファイル一覧だ。

[codepad]
print "$_\n" for </*>

glob("*")または<*>は、以下とほぼ等価である。

[codepad]
my @files = do{
  opendir my $dh, '.' or return;
  my @f = grep !/^\./, readdir($dh);
  closedir $dh;
  @f;
};
print "$_\n" for @files;

「ほぼ」、と書いたのは、列挙されるファイルは同じでも、その順番まで同じであることは保証されていないからだ。

なお、globの表記は正規表現ではない。このあたりは

void GraphicWizardsLair( void ); // シェルで使う「*.jpg」みたいなglobと、PerlやJavaScript等で使う「.+\.jpg$」という正規表現は全く別物だけど、混同されている気がした
これはおそらくunixシェルのグロブとか、それを真似たMS-DOSプロンプトの「*」による「任意の文字の連続にmatch」と誤解しているからだろう。

でも指摘されている通りである。

そういうわけなので、globに関してはその定義どおり、「シェルのグロブどおりにファイル名を展開する」と説明すべきであり、「ディレクトリの内容を取り出す」のであれば、readdir()を紹介すべきであろう。

私個人は、ファイル名の列挙はgrepreaddirでやっていて、globは滅多に使わない。globが欲しい場面は、大抵one-linerで間に合ってしまうので、perlのそれを使うまでもないというのが一つと、後述のように実はFile::Globのwrapperに過ぎず、よって定義を知らぬ間他のモジュールに上書きされている可能性もゼロではないからだ。

asin:4873113148
PERL HACKS
(日本語版)
[英語版]

前述のとおり、glob()は perl 5.6.0 よりFile::Globのwrapperとなっている。また、*CORE::GLOBAL::globにcode referenceを設定することで、任意の目的にglob()を使うことを用いることが出来る。PERL HACKSのHack #90に例がある。しかしこのHackの例もまた、*CORE::GLOBAL::globにコードをインストールしており、lexical pragmaにはなっていない。Perl 5.10以降であればlexicalにするのは可能だが、それは読者の宿題ということで。

Dan the Regular Expressionist