2

私の仕事は:

  1. コマンド ラインから、ディレクトリ、並べ替えの種類、並べ替えの順序を読み取ります。
  2. ファイル名をソートし、サイズと日付で印刷します。

これが私がこれまでに得たものです。

#!/usr/bin/perl

use 5.010;
use strict;
use warnings;

use Getopt::Long;
my $dir = "";
my $sortby = "";
my $order = "";
my $result;

$result = GetOptions (
                    'dir=s'  => \$dir,                # specify derictory
                   'sortby=s'    =>  \$sortby,        # 'name' or 'date'
                   'order=s'     =>  \$order);        # 'asc'- or 'des'-ending order of sorting

print "derictory = $dir, sortby  = $sortby, order = $order \n\n";


opendir (DH, $dir)or die "couldn open dericroty: $!\n";
my @filenames = grep ! /^\./, readdir DH;
closedir (DH);

if ($sortby eq "name") {

     if ($order eq "asc") {
         foreach my $name (sort {lc $a cmp lc $b} @filenames) {
         my @statinfo = stat("$dir/$name");
         print "$name\tsize= " . $statinfo[7] . ",\t last modified=" . 
         scalar(localtime($statinfo[9])) . "\n";
         }
     }
     elsif ($order eq "des") {
         foreach my $name (sort {lc $b cmp lc $a} @filenames) {
         my @statinfo = stat("$dir/$name");
         print "$name\tsize= " . $statinfo[7] . ",\t last modified=" . 
         scalar(localtime($statinfo[9])) . "\n";
         }
     }      
}


if ($sortby eq "date") {
    if ($order eq "asc") {
        @filenames = sort { -M "$dir/$a" <=> -M "$dir/$b" } (@filenames);   
        print  join ("\n", @filenames);
    }    
    elsif ($order eq "des") {
        @filenames = sort { -M "$dir/$b" <=> -M "$dir/$a" } (@filenames);   
        print  join ("\n", @filenames);
    }    
}

問題は、変更日でソートする必要がある場合、サイズと日付を含むファイル名のリストを印刷する方法がわからないことです。私は stat 関数を使用することになっていると思いますが、名前をループして各統計を取得することはできません。
私が上に持っているのは、基本的に私がググってまとめたものだけです。

4

3 に答える 3

3

ここでは、この問題について別の方法で考えます。重要なポイント:

  1. 簡単なことを行う小さな関数を作成し、それらの関数を組み合わせてプログラムを構築します。

  2. すべての情報を便利なデータ構造(この例ではハッシュのリスト) に収集すると、プログラムのアルゴリズム的/論理的側面が簡単かつ自然になります。

簡単にするために、この例ではオプションの解析を無視し、代わりに params を通常のコマンド ライン引数として受け入れます。

use strict;
use warnings;

main();

sub main {
    my ($dir, $sortby, $order) = @ARGV;

    my @contents = read_dir($dir);
    my $sb       = $sortby eq 'date' ? 'mtime' : 'path';
    my @sorted   = sort { $a->{$sb} cmp $b->{$sb}  } @contents;
    @sorted      = reverse(@sorted) if $order eq 'des';

    for my $fi (@sorted){
        print $fi->{path}, ' : ', $fi->{mtime}, "\n";
    }
}

sub read_dir {
    # Takes a dir path.
    # Returns a list of file_info() hash refs.
    my $d = shift;
    opendir(my $dh, $d) or die $!;
    return map  { file_info($_) }  # Collect info.
           map  { "$d/$_" }        # Attach dir path.
           grep { ! /^\.\.?$/ }    # No dot dirs.
           readdir($dh);
}

sub file_info {
    # Takes a path to a file/dir.
    # Returns hash ref containing the path plus any stat() info you need.
    my $f = shift;
    my @s = stat($f);
    return {
        path  => $f,
        mtime => $s[9],
    };
}
于 2013-10-10T03:26:17.657 に答える
2

データの特定のプロパティで並べ替える場合は、Schwartzian Transformを確認することをお勧めします。これは、変更時間でソートするために使用する方法の基本的な例です。

use strict;
use warnings;

use constant MTIME_STAT_INDEX => 9;
use constant FILENAME_INDEX => 0;
use constant MTIME_INDEX => 1;

# Grab a list of files in the current folder
my $some_dir = '.';
opendir(my $dh, $some_dir) || die "can't opendir $some_dir: $!";
my @fileNames = readdir $dh;
closedir $dh;

# Use a Schwartzian transform to generate a sorted list of <file_name, mtime> tuples 
my @sortedByMtime = 
    map { $_ }
    sort { $a->[MTIME_INDEX] cmp $b->[MTIME_INDEX] } 
    map { [$_, (stat($_))[MTIME_STAT_INDEX]] } @fileNames;

# Print the file name and mtime
for my $sortedRecord (@sortedByMtime) {
    print $sortedRecord->[FILENAME_INDEX] . "\t" . $sortedRecord->[MTIME_INDEX] . "\n";
}

1;

変換を外側から読む (つまり、最後から開始し、開始に向かって作業する) と役立つ場合があります。ファイル名のリストから始めて、 map を使用して、フォームのエントリを含む配列を生成します<file_name, modified_time>。次に、このリストを変更時刻でソートし、最終マップ (つまり、最初のマップ) を使用して不要なプロパティを取り除くことができます。この例では、何も取り除いていませんが、理論的には、この構築された構造に他のプロパティ (ファイル サイズなど) を含めることができることを理解していただければ幸いです。

これは、概念実証として開始することを目的としています。効率、エラー処理、出力の見栄えについてはあまり考慮していません。

于 2013-10-10T01:35:30.113 に答える
1

File::statを見る必要があります。このモジュール (Subversion に付属) を使用すると、ファイルに関するあらゆる種類の情報に簡単にアクセスできます。

Time::Pieceも見てください。このモジュールを使用すると、日付と時刻を簡単にフォーマットできます。

また、4 つの個別の並べ替えルーチンを使用することについても心配しません。代わりに、配列標準の昇順で必要なものを並べ替えるだけです。次に、印刷する前に、ユーザーが降順を要求したかどうかを確認します。ユーザーが降順を要求した場合は、を使用して並べ替えられた配列を逆にすることができます。

Referencesを使用しています。ファイル名を保存している配列には、文字列ではなく、ハッシュへの参照が含まれています。このように、配列内の各エントリには、ファイルに関する 4 つの個別の情報が含まれています。

また、Pod::Usage を使用して、 POD のドキュメントに基づいてメッセージを出力しています。POD は、プログラムに関するドキュメントを保存するためのかなり単純な形式です。ユーザーは、次のperldocコマンドを使用してポッドを表示できます。

$ perldoc prog.pl

pod2htmlまたは、ドキュメントを HTML に変換するなどのコマンドを使用することもできます。これらのさまざまな Perldoc および POD コマンドは、Perl ディストリビューションに付属しています。POD を学び、幅広く使用することを強くお勧めします。プログラムのドキュメントをプログラムに保持し、ドキュメントのあらゆる種類の形式を作成できるようにします。(テキスト、HTML、マンページ、マークダウン、wiki など)。

#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);
use autodie;

# All of these are standard Perl module and come with all distributions
# or Perl

use Time::Piece;
use File::stat;
use Getopt::Long;
use Pod::Usage;
use File::Basename;

my ( $directory, $sort_order, $sort_descending, $help );

#
# Using pod2usage to print out my messages
#
GetOptions (
    "directory=s"   => \$directory,
    "sort=s"        => \$sort_order,
    "descending"    => \$sort_descending,
    "help"          => \$help,
) or pod2usage;

if ( $help ) {
    pod2usage ( -message => qq(Use command 'perldoc print_dir.pl' for complete documetation) );
}

if ( not ( defined $directory and defined $sort_order ) ) {
    pod2usage ( -message => qq(Must use parameters "directory" and "sort") );
}

if ( $sort_order ne "name"  and
     $sort_order ne "ctime" and
     $sort_order ne "size"  and
     $sort_order ne "mtime" ) {
     die qq(Sort order must be "name", "size", "ctime", or "mtime"\n);
 }

opendir ( my $dir_fh, $directory );         #Will autodie here if directory doesn't exist

my @files;
while ( my $file = readdir $dir_fh ) {
    $file = "$directory/$file";
    next if not -f $file;

    #
    # Note I'm using File::stat to get the info on the files
    #

    my $stat = stat $file or die qq(Couldn't stat file "$file"\n);
    my %file;
    $file{NAME}  = basename $file;
    $file{CTIME} = $stat->ctime;
    $file{MTIME} = $stat->mtime;
    $file{SIZE}  = $stat->size;
    #
    # I'm storing this information in a hash and pushing a Hash Reference
    #
    push @files, \%file;    #Pushing a reference to the hash
}
closedir $dir_fh;

my @sorted_files =  sort file_sort @files;

#
# I am using the fact that my hash keys and my sort options
# are very similar. One routine sorts all which ways
#
sub file_sort {
    my $sort_by = uc $sort_order;
    if ( $sort_order eq "name" ) {
        return $a->{$sort_by} cmp $b->{$sort_by};
    } else {
        return $a->{$sort_by} <=> $b->{$sort_by};
    }
}

#
# If the user wants descending order, reverse the array
#
if ( $sort_descending ) {
    @sorted_files = reverse @sorted_files;
}

#
# I'm using 'printf' to print out a nice report.
# My $format is the format of the report, and I
# can use it for the title or the body.
#
my $format = "%-20.20s  %-10d  %-11.11s  %-11.11s\n";
( my $title_format = $format ) =~ s/d/s/;
printf $title_format, "Name", "Sixe", "Mod-Time", "C-Time";
say join "  ", "=" x 20, "=" x 10, "=" x 11, "=" x 11;
for my $file ( @sorted_files ) {
    #
    # The "->" dereferences the hash
    # Note how I use Time::Piece to format my time
    #
    my $mtime = Time::Piece->new ( $file->{MTIME} );
    my $ctime = Time::Piece->new ( $file->{CTIME} );
    printf $format, $file->{NAME}, $file->{SIZE}, $mtime->ymd, $ctime->ymd;
}

#
# Here be the Plain Old Documention (POD) This is the standard
# way to document Perl programs. You can use the "perldoc" program
# to print it out, and pod2usage to print out bits and pieces.
#

=pod

=head1 NAME

print_dir.pl

=head1 SYNOPSIS

    print_dir.pl -sort [name|size|mtime|ctime] -directory $directory [ -descending ]

=head1 DESCRIPTION

This program does somee amazing wonderful stuff...

=head1 OPTIONS

=over 4

=item *

-sort

(Required) Sort order of directory parameters can be C<name>, C<size>, C<mtime>, C<ctime>

=item *

-directory

(Required) Name of the directory to print

=item *

-descending

(Optional) Sort in descending order instead of ascending order

=back

=cut
于 2013-10-10T03:23:43.070 に答える