Perl 2008年のファイルオープン

第1回 Perlの文法の基本:ITpro という記事の はてブコメントを見ていたら、Perl なすごい人達が文句言ってた。

otsune otsune 2006年のhyuki Catalyst記事を載せるのもアレなのに2003年の記事を載せるのは無しだろ……open IN, ...のあたりは有害情報なので全力で見逃せ

TAKESAKO TAKESAKO ちょw→出典:日経Linux 2003年7月号 125ページより

miyagawa miyagawa 2008年にこの記事はねーよ、と思ったら2003年の記事をいまさら再掲か。なんでわざわざ古い記事を新しいものかのように出して混乱させる?

問題があるというソースコードはこんなの。

open IN, '</etc/passwd';

えー! どこが問題あるのかさっぱり分からん!!!!!!

調べてみた

2008年流の Perl な書き方を調べるなら perl-users.jp

早速見つけた。oldtype と modern の書き方が比較されている。

open

  • oldtype: open FH, "filename" or die $!;
  • modern: open my $fh, '<', 'filename' or die $!; または file('filename')->open('r') とか
Perl 5 今昔 - Perl-users.jp

まず $! が分からない

oldtype の $! すら理解できない自分…。Perl は特殊変数が多くて大変なんだよなぁ。しかも、検索エンジンで検索できないのが困り者。

こういうときは、perlvar を眺める。どうやら $! はエラーメッセージになるらしい。

If used as a string, yields the corresponding system error string.

どれどれ。

> perl -e "open FH, '__not__found__' or die $!"
No such file or directory at -e line 1.

おー、確かに。

数値リテラルだとエラーコードになるらしい。どれどれ...

> perl -e "open FH, '__not__found__' or print int($!)"
2

ほんとだ。

MODE を分ける

それでは、modern その1のコードを見てみる。

open my $fh, '<', 'filename' or die $!;

謎だ。

困ってても仕方がないので、perldoc の open を見てみた。いくつもの書き方があるようだ。

open FILEHANDLE,EXPR 
open FILEHANDLE,MODE,EXPR
open FILEHANDLE,MODE,EXPR,LIST 
open FILEHANDLE,MODE,REFERENCE 
open FILEHANDLE 

なるほど。今回は2番目の形になってる。MODE を分離して書けるのはセキュリティ的にも素敵だ。これは明日からでも使いたい感じ。


my $fh の謎

問題は my $fh。なんだこの書き方は。

open の説明をみても良く分からなかったので、perlopentut を見てみた。

そしたら、Indirect Filehandles にズバリそのものの記述が(日本語は私が訳したもの)。

open の第一引数はファイルハンドルのリファレンスを指定することもできます。Perl 5.6 では、第一引数が初期化されていない場合、Perl はファイルハンドルを自動的に作成し、第一引数にリファレンスを代入します。

open's first argument can be a reference to a filehandle. As of perl 5.6.0, if the argument is uninitialized, Perl will automatically create a filehandle and put a reference to it in the first argument

なるほど。初期化されてない変数を渡せるわけね。

しかし、メリットがいまいち分からん。続きを読む(同じく、日本語は私が勝手に訳したもの)。

Indrect filehandle を使うと、名前空間の扱いが簡単になります。ファイルハンドルはパッケージ空間に対して global なので、例えば2つのサブルーチンで INFILE を開くとクラッシュしてしまいます。indirect filehandle を利用して my $infile を開いた場合にはクラッシュする心配はありませんし、それ以後に名前の衝突が発生する恐れもありません。

Indirect filehandles make namespace management easier. Since filehandles are global to the current package, two subroutines trying to open INFILE will clash. With two functions opening indirect filehandles like my $infile , there's no clash and no need to worry about future conflicts.

なるほど。これは安心。

open IN, ... 形式がグローバル変数で、open my $in, ... がローカル変数、というイメージ。

読んだり閉じたりするには次のようにする。

print <$fh>;
close $fh;

Perl 5.6 以降限定だけど、これも明日から使えそうなテクニックだ。

modern その2

modern その2はお手上げ。

file('filename')->open('r')

file 関数ってなんだ?? なんかのモジュール??

(追記) コメント欄でkzysさんに教えてもらいました。Path::Class モジュールのようです(Path::Class)。ありがとうございます。ファイルやディレクトリをたどるのが簡単になりそうですね。

まとめ

  • Perl は奥が深い。難しい。
  • ハブサイトは初心者にとってありがたい。

(追記) 弾さんも添削してた。ありがたや。参考になります。