読者です 読者をやめる 読者になる 読者になる

初めてのPerl 第11章

練習問題の回答をメモ。今回は、答えを見て自分の書いたプログラムが恥ずかしくなった。この章はいろいろと勉強になったし、また読み返そう。

ex11-1
#!/usr/bin/perl
use strict;

print "Enter input file name: ";
chomp(my $input_file = <STDIN>);

print "Enter output file name: ";
chomp(my $output_file = <STDIN>);

print "Enter search pattern: ";
chomp(my $pattern = <STDIN>);

print "Enter substitute string: ";
chomp(my $string= <STDIN>);

open INPUT, "<$input_file"
    or die "Cannot open input file: $!";
open OUTPUT, "> $output_file"
    or die "Cannot create output file: $!";

select OUTPUT;

while (<INPUT>) {
#  s/$pattern/\u\L$1\E/g;
  s/$pattern/$string/g;
  print;
}

ex11-1 の反省点

chomp を繰り返し使ってるのが目に付くね。プロンプトを表示してから、「1行読み込んでそれを chomp して返す」サブルーチンを作ったほうが便利だよ。


ユーザから入力ファイルを指定してもらったら、速攻でオープンしよう。入力ファイル名が間違っていたら、残りのパラメータすべてを入力してもらっても無駄になっちゃうよ。


出力ファイルはオープンする前に既存のファイルが無いか必ずチェックしよう。既存のファイルを出力用にオープンするだけで、その内容は消されてしまうよ。

die "won't overwrite existing file" if -e $output_file;
ex11-2
#!/usr/bin/perl
use strict;

# @ARGV はコマンドライン引数が入ってる p108
foreach (@ARGV) {
  &check($_);
}

sub check {
  print "$_[0] is readable.\n" if -r $_[0];
  print "$_[0] is writable.\n" if -w $_[0];
  print "$_[0] is executable.\n" if -x $_[0];
  print "$_[0] exists .\n" if -e $_[0];
}

ex11-2 の反省点

サブルーチンで表示を行っちゃってるね。自分が決めたこのサブルーチンの役割は「引数として渡されたファイルのパーミッションと存在を確認すること」だったから、「ついでに表示も行う」というのはやりすぎだね。確認結果の文字列を戻り値とするのが良かったかな。

ex11-3
#!/usr/bin/perl
use strict;

my $oldest_file = shift @ARGV;

# @ARGV はコマンドライン引数が入ってる p108
foreach my $filename (@ARGV) {
  # -M で最後に変更されてからの日数を調べる p190
  if (-M $oldest_file <= -M $filename) {
    $oldest_file = $filename;
  }
}
my $how_old = -M $oldest_file;
printf "%s is the oldest. It is not modified %.0f days.\n", $oldest_file, $how_old;

ex11-3 の反省点

冒頭でコマンドライン引数に指定されているファイル名の個数をチェックし忘れているね。このプログラムの目的は、最も古いファイル名を得ることだから、ファイルが指定されていなかったら最も古いものなど存在しないよね。

die "No file names supplied!\n" unless @ARGV;


このコードに限った話ではないけど、特別な下線ファイルハンドルについていまひとつ理解が足りていないみたい。p.327 「しかし、より重要なことは、このプログラムがチェックしている最中に、だれかがファイルを更新したら何が起こるかという点です。〜」という部分の説明がよく理解できなかった。特別なファイルハンドル「_」と「$_」は違うのかな?後で調べよう。
追記:p.199 に「_」と「$_」は異なる機能に似たような名前が付けられているというケースの1つですと書いてあった。だけど、まだ「_」と「プログラムを実行中にファイルを更新したら何が起こるか」という話の関連がよく理解できないな…。

全体の反省点

サブルーチン化できる部分が無いか、積極的に考えよう。
サブルーチンの「役割」が何かしっかり考えて実装しよう。余計なことをやらせてないかな?
特別なファイルハンドル「_」を使うべき場面と、考えられる副作用をきちんと理解しよう。