11章ファイルハンドルとファイルテスト 練習問題3

コマンドラインからファイル名のリストを受け取って、そのうち最も古いファイルの名前とその古さを日数単位で表示するプログラムを書いてください。
初めてのPerl p.200

#! /usr/local/bin/perl

use strict;
use warnings;


#このプログラムの説明
print "引数として受け取ったファイル名のリストから最も古いファイルの名前とその古さを表\示するプログラムです。\n";

my @files = @ARGV;
my ($filename, $filestat) = ('nothing', 0);

#forで順次処理していく(最高水位線アルゴリズムを用いる)
for (@files) {
    my $days = (-M $_);

    if ($days > $filestat) {
	($filename, $filestat) = ($_, $days);
    }
}

$filestat = $filestat & (0xFFFF);
print "[$filename] - $filestat日\n";
  • Mファイルテストが浮動小数点数で経過日数を表現することに面食らい、更に剰余を用いての小数点以下の切捨てができなくて困りました。

ですが11章で学んだビット演算子を思い出して、16進数(FFFF)と論理演算をしたところ、うまく小数点以下が切り捨てられました(但し10進数69904までしか対応していないのですが)。

きっともっと上手な切捨て方法があるはず。
解答を見てみます。

むむ。予想外に論理演算子は使っていませんでした。
それはさておき、いけてない箇所を箇条書きに。

    • 無駄な初期化処理はいらない。
    • その代わりに、初期処理で一つ目の引数を処理する。
    • 引数にファイル名を渡されなかったら、即座に終了してもデメリットはない。
  • ファイルテストのデフォルトの対象オペランドは$_。これは省略可。
  • 短いif文は一行にまとめる。
    • (then処理)-(if)という記述方法を用いていて、一行が長すぎるときは(if)を次の行にもっていき、1つタブをおけばよい。

小数点以下の切捨てに関しては、printf命令で解決。
論理演算子を用いるのはわかりづらいし、大きい値には対応できなくなる。
よって素直にprintf命令を使用するのが良い。

修正完了。

#! /usr/local/bin/perl

use strict;
use warnings;


#このプログラムの説明
print "引数として受け取ったファイル名のリストから最も古いファイルの名前とその古さを表\示するプログラムです。\n";

die "ファイルがありません!\n" unless @ARGV;

my $filename = shift @ARGV;
my $filestat = -M  $filename;

my @files = @ARGV;

#forで順次処理していく(最高水位線アルゴリズムを用いる)
for (@files) {
    my $day = (-M);

    ($filename, $filestat) = ($_, $day)
	if ($day > $filestat);
}


printf "[%s] - %6.0f日\n", $filename, $filestat;

C:\Perl\hajip>perl hoge.pl tes1.txt test.txt hatena.txt
引数として受け取ったファイル名のリストから最も古いファイルの名前とその古さを表示するプログラムです。
[test.txt] - 11日

C:\Perl\hajip>

大丈夫ですね。