12章 練習問題1

次のようなプログラムを書いてください。まずユーザからディレクトリ名を入力してもらい、そのディレクトリに移動します。もしユーザが入力した行に空白文字だけしか含まれていなければ、デフォルトの動作として、そのユーザのホームディレクトリに移動します。移動したら、そのディレクトリの内容をアルファベット順に表示します。
初めてのPerl P.207

今回はすらすらとコードが書けました。
id:kidd-number5さんから頂いた、コメントを先に書いていくといいとのアドバイスを実践してみた効果でしょうか?
いつもより段違いに速かったです。
よく聞きますが、やはり行き当たりばったりなコーディングはイクナイですね。
大雑把でいいから全体を意識するのがプログラムを速く書く秘訣なんでしょうか。


さてさて、作成コードはこちらです。

#! /usr/local/bin/perl

use strict;
use warnings;

#プログラムの説明を出力
print "指令されたディレクトリのファイルを表示するプログラムです。\n";

#ユーザにディレクトリ名を入力してもらう。メッセージを出力した後、標準入力を読み込む
print "ディレクトリ名を入力してください。\n\n";
chomp(my $dir = <STDIN>);

#何も入力されていないか判定する
die "何も入力されませんでした。実行を終了します。\n"
    if ($dir eq '');

#指定ディレクトリに移動する。空白文字のみ入力された場合は、ユーザのホームディレクトリに移動する。入力された場合は、指定ディレクトリに移動
if ($dir =~ /\s+/) {
    print "空白文字しか入力されていません。代わりにホームディレクトリへ移動します。\n";
    chdir or die "ディレクトリを移動できませんでした。\n";
} else {
    chdir "$dir" or die "ディレクトリを移動できませんでした。\n";
}

#ドットで始まるファイルを除く、移動先ディレクトリの内容を昇順に表示する(ドットで始まるファイルは不要なので、グロブを用いる)

my @files = glob("*");
print "移動先ディレクトリの内容を表\示します。\n";
for (sort @files) {
    print "$_\n";
}

実行結果は以下のようになりました。

C:\Perl\hajip>perl hoge.pl
指令されたディレクトリのファイルを表示するプログラムです。
ディレクトリ名を入力してください。

c:/perl/
移動先ディレクトリの内容を表示します。
#ChangeLog#
ChangeLog
ChangeLog~
archive
bin
cpan
cpan.cgi
cpan.pl
eg
foo.bat
hajip
hoge.pl
hoge.pl~
hoge.txt
html
html-downcase.pl
jcode.pl
lib
site

C:\Perl\hajip>perl hoge.pl
指令されたディレクトリのファイルを表示するプログラムです。
ディレクトリ名を入力してください。


空白文字しか入力されていません。代わりにホームディレクトリへ移動します。
移動先ディレクトリの内容を表示します。
bin
calc.pl
font-setup.el
perl
TUTORIAL.ja


C:\Perl\hajip>perl ex12-2.pl
指令されたディレクトリの、ドットファイルを含む全てのファイルを表示するプログラムです。
ディレクトリ名を入力してください。


何も入力されませんでした。プログラムの実行を終了します。

ふむ。問題なさそう。
それでは解答を参考に問題箇所の洗い出し開始。

  • 正規表現の書き方が違った
    • わ、バグだ。これについては後述します。
  • sort命令は不要
    • ディレクトリハンドルと同様で、グロブで得られるファイルはdirコマンドで返される順番と同じ。よってソートは不要。
  • ユーザに対する出力メッセージは、明示的に。
    • エラーメッセージの場合、使い方のどこがどうしていけないのかを教えてあげる事が重要。
    • 経過を伝えるメッセージには、何をどうするのかを明らかにする(5W2Hを意識)


正規表現のバグですが、

($dir =~ /\s+/)

これだとユーザが指定したディレクトリ情報に空白文字が含まれているだけで「空白文字しか入力されていません。代わりにホームディレクトリへ移動します。」と表示されてしまいます。
ですので、アンカーを用いて、

($dir =~ /^\s+$/)

こう書くのが正答でしょうね。


以上の点を踏まえて、書き直してみます。

#! /usr/local/bin/perl

use strict;
use warnings;

#プログラムの説明を出力
print "指令されたディレクトリのファイルを表\示するプログラムです。\n";

#ユーザにディレクトリ名を入力してもらう。メッセージを出力した後、標準入力を読み込む
print "ディレクトリ名を入力してください。\n\n";
chomp(my $dir = <STDIN>);

#何も入力されていないか判定する
die "何も入力されませんでした。プログラムの実行を終了します。\n"
    if ($dir eq '');

#指定ディレクトリに移動する。空白文字のみ入力された場合は、ユーザのホームディレクトリに移動する。入力された場合は、指定ディレクトリに移動
if ($dir =~ /^\s+$/) {
    print "空白文字しか入力されていません。代わりにホームディレクトリへ移動します。\n";
    chdir or die "ホームディレクトリに移動できませんでした。\n";
} else {
    chdir "$dir" or die "$dir ディレクトリに移動できませんでした。\n";
    print "$dir ディレクトリへ移動します。\n";
}

#ドットで始まるファイルを除く、移動先ディレクトリの内容を昇順に表示する(ドットで始まるファイルは不要なので、グロブを用いる)

my @files = glob("*");
print "移動先ディレクトリの内容を表\示します。\n";
for (@files) {
    print "$_\n";
}


何度もテストしたのですが、指定ファイルディレクトリに

c:(空白)

を入力するとカレントディレクトリに対してchdirしてしまいますね。
ここはむしろ置換演算子で空白を置き換えるのがベターでしょうか。