11.7 練習問題2

コマンドラインならファイル名のリストを受け取って、その1つ1つについて、読み出し可能か、書き込み可能か、実行可能か、存在しないかを表示するプログラムを書いてください
はじめてのPerl p.200

それではまず自作コードを。

#! /usr/local/bin/perl

use strict;
use warnings;


#全てのファイルテストを行い、結果を表示させる関数
sub test {
    my $file = $_[0];


    #まずファイルが存在するかチェックする。存在するときのみ他のファイルテストを行う
    if (-e $file) {
	print "\tファイルが存在します\n";

	    if (-r $file) {
		print "\t読み出し可能\です\n";
	    } else {
		print "\t読み出し不可能\です\n";
	    }
	    if (-w $file) {
		print "\t書き込み可能\です\n";
	    } else {
		print "\t書き込み不可能\です\n";
	    }
	    
	    if (-x $file) {
		print "\t実行可能\です\n\n";
	    } else {
		print "\t実行不可能\です\n\n";
	    }

    } else {
	print "\tファイルが存在しません\n";
	print "\tこのファイルへのテストを終了します\n\n";
    }

}
#全ての引数を処理するループ。判定して表示する。
for (@ARGV) {
    print "[$_]\n";
    test($_);
}

あんまりif文使いたくないけど、致し方無いのか。
さてさて、プログラムを実行してみます。

C:\Perl\hajip>perl hoge.pl notfound.txt tes1.txt tes2.txt
[notfound.txt]
ファイルが存在しません
このファイルへのテストを終了します

[tes1.txt]
ファイルが存在します
読み出し可能です
書き込み可能です
実行不可能です

[tes2.txt]
ファイルが存在します
読み出し可能です
書き込み可能です
実行不可能です

ふむ。問題なし。


解答を参考に、いけてない部分を箇条書きにすると

  • if文多すぎ。
    • メッセージは減ることになるが、もっとコードの見た目を良くできる。
    • どの程度までユーザにメッセージを伝えるべきか、さじ加減が課題
  • if文の入れ子が嫌。
    • return使ってサブルーチンの途中で随時戻していく
  • ファイルテストごとにシステムコールしている
    • ファイルテストを行うとシステムコールされてしまう。何度もファイルテストを行うときは"_"ファイルハンドルを使用して、一度目のファイルテストで使用したstatバッファのデータを再利用するとグッド。
  • if文が無駄にもっさりしている
    • 一行に収まりそうなときは収める
  • if文の箇所のみならず、全体的にコードがもっさりしている、わかりづらい
    • 常にプログラムを短く、簡単に書けないか意識する
  • ルーチン同士が依存しあっている
    • 常にモジュール強度、結合度を意識

書きなおしてみます。

#! /usr/local/bin/perl

use strict;
use warnings;

#引数に対してファイルテストを行い、順次その結果を出力するサブルーチン
sub test {
    my $file = shift @_;

    unless (-e $file) {
	print "\t$file doesn't exist\n";
	return;
    }

    print "\t読み出し可能\です\n" if (-r _);
    print "\t書き込み可能\です\n" if (-w _);
    print "\t実行可能\です\n"     if (-x _);
    print "\n";
}

for (@ARGV) {
    print "[$_]\n";
    &test($_);
}

おおっ、結構きれいになったんじゃないかと。
43行→24行へダイエット成功。