我的任务是:
这是我到目前为止所得到的。
#!/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函数,但我不能遍历名称,并得到每个统计数据 我上面所有的基本上是我能够谷歌和放在一起。
答案 0 :(得分:3)
这是思考问题的另一种方式。要点:
编写执行简单操作的小功能,并构建您的程序 将这些功能组合在一起。
如果您在方便的数据中收集所有信息 结构(在本例中,哈希列表),算法/逻辑 该计划的各个方面变得简单而自然。
为简单起见,此示例忽略选项解析,而只是接受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],
};
}
答案 1 :(得分:1)
如果您要按数据的某些属性进行排序,可能需要查看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>
形式的条目的数组。然后,您可以按修改时间对此列表进行排序,并可以使用最终映射(即第一个映射)来去除任何不需要的属性。在这个例子中,我没有删除任何东西,但我希望你能理解你在理论上可以在这个构建的结构中有其他属性,例如文件大小。
这只是为了让您开始作为概念证明 - 我没有考虑效率,错误处理或使输出相当漂亮。
答案 2 :(得分:0)
你应该看看File::stat。该模块(Subversion附带)允许您轻松访问有关该文件的各种信息。
您还应该查看Time::Piece。此模块允许您轻松格式化日期和时间。
我也不担心有四个单独的排序例程。相反,只需按照数组标准升序对所需内容进行排序。然后,在打印之前,查看用户是否请求降序。如果用户确实请求降序,则可以使用reverse来反转已排序的数组。
我正在使用References。我存储文件名的数组不包含字符串,而是包含引用到哈希。这样,我的数组中的每个条目都包含有关我文件的四个独立信息。
我也使用Pod :: Usage根据我的POD documentation打印消息。 POD是一种相当简单的格式,用于存储有关程序的文档。用户可以使用perldoc
命令显示pod:
$ perldoc prog.pl
或者,他们可以使用pod2html
等命令将文档转换为HTML。这些各种Perldoc和POD命令随Perl发行版一起提供。我强烈建议您学习POD并广泛使用它。它将您的程序文档保存在您的程序中,并允许您为您的文档生成各种格式。 (文本,HTML,联机帮助,降价,维基等)。
#! /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